В чем разница между SimpleNamespace и пустым определением класса?

Кажется, что все работает в любом случае. В чем преимущество (кроме приятного repr) использования types.SimpleNamespace? Или это одно и то же?

>>> import types
>>> class Cls():
...     pass
... 
>>> foo = types.SimpleNamespace() # or foo = Cls()
>>> foo.bar = 42
>>> foo.bar
42
>>> del foo.bar
>>> foo.bar
AttributeError: 'types.SimpleNamespace' object has no attribute 'bar'

Ответ 1

Это хорошо объясняется в описании types. Он показывает, что types.SimpleNamespace примерно эквивалентен этому:

class SimpleNamespace:
    def __init__(self, **kwargs):
        self.__dict__.update(kwargs)

    def __repr__(self):
        keys = sorted(self.__dict__)
        items = ("{}={!r}".format(k, self.__dict__[k]) for k in keys)
        return "{}({})".format(type(self).__name__, ", ".join(items))

    def __eq__(self, other):
        return self.__dict__ == other.__dict__

Это дает следующие преимущества перед пустым классом:

  • Он позволяет инициализировать атрибуты при построении объекта: sn = SimpleNamespace(a=1, b=2)
  • Он предоставляет читаемый repr(): eval(repr(sn)) == sn
  • Он отменяет сравнение по умолчанию. Вместо сравнения id() вместо этого сравниваются значения атрибутов.