какая самая большая разница между dir и __dict__ в python

class C(object):
    def f(self):
        print self.__dict__
        print dir(self)
c = C()
c.f()

выход:

{}

['__class__', '__delattr__','f',....]

почему в self нет буквы "f".__dict__


person shellfly    schedule 16.01.2013    source источник


Ответы (3)


dir() делает гораздо больше, чем просто ищет __dict__

Прежде всего, dir() — это метод API, который знает, как использовать такие атрибуты, как __dict__, для поиска атрибутов объекта.

Однако не все объекты имеют атрибут __dict__. Например, если вы добавите в свой пользовательский класс атрибут __slots__, экземпляры этого класса не будет иметь атрибута __dict__, но dir() по-прежнему может отображать доступные атрибуты для этих экземпляров:

>>> class Foo(object):
...     __slots__ = ('bar',)
...     bar = 'spam'
... 
>>> Foo().__dict__
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Foo' object has no attribute '__dict__'
>>> dir(Foo())
['__class__', '__delattr__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__slots__', '__str__', '__subclasshook__', 'bar']

То же самое относится ко многим встроенным типам; lists не имеют атрибута __dict__, но вы все равно можете перечислить все атрибуты, используя dir():

>>> [].__dict__
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'list' object has no attribute '__dict__'
>>> dir([])
['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__delslice__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getslice__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__setslice__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']

Что dir() делает с экземплярами

Экземпляры Python имеют свои собственные __dict__, но и их класс тоже:

>>> class Foo(object):
...     bar = 'spam'
... 
>>> Foo().__dict__
{}
>>> Foo.__dict__.items()
[('__dict__', <attribute '__dict__' of 'Foo' objects>), ('__weakref__', <attribute '__weakref__' of 'Foo' objects>), ('__module__', '__main__'), ('bar', 'spam'), ('__doc__', None)]

Метод dir() использует оба этих __dict__ атрибута, и атрибут object для создания полного списка доступных атрибутов экземпляра, класса и всех предков класса. .

Когда вы устанавливаете атрибуты для класса, экземпляры также видят их:

>>> f = Foo()
>>> f.ham
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Foo' object has no attribute 'ham'
>>> Foo.ham = 'eggs'
>>> f.ham
'eggs'

потому что атрибут добавлен в класс __dict__:

>>> Foo.__dict__['ham']
'eggs'
>>> f.__dict__
{}

Обратите внимание, что экземпляр __dict__ остается пустым. Поиск атрибутов в объектах Python следует иерархии объектов от экземпляра к типу и к родительским классам для поиска атрибутов.

Только когда вы устанавливаете атрибуты непосредственно в экземпляре, вы увидите атрибут, отраженный в __dict__ экземпляра, в то время как класс __dict__ остается неизменным:

>>> f.stack = 'overflow'
>>> f.__dict__
{'stack': 'overflow'}
>>> 'stack' in Foo.__dict__
False

TLDR; или резюме

dir() не просто ищет __dict__ объекта (который иногда даже не существует), он будет использовать наследие объекта (его класс или тип, а также любые суперклассы или родители этого класса или типа), чтобы дать вам полную информацию. изображение всех доступных атрибутов.

Экземпляр __dict__ — это просто «локальный» набор атрибутов в этом экземпляре, и он не содержит всех атрибутов, доступных в экземпляре. Вместо этого вам нужно также посмотреть на класс и дерево наследования класса.

person Martijn Pieters    schedule 16.01.2013
comment
dir также будет смотреть на __dir__, если он реализован, что может возвращать строки для вещей, которые даже не реализованы как формальные свойства или атрибуты, а просто лениво реализованы, например, в __getattr__. - person PaulMcG; 16.01.2013
comment
@PaulMcGuire: я не хотел вдаваться в подробности того, что делает dir(); это длинный ответ, и мне не нужно было включать эту деталь, чтобы понять суть. :-) - person Martijn Pieters; 16.01.2013
comment
См. в чем разница между dir(self) и self.__dict__ для более краткого ответа. - person Peterino; 26.02.2017
comment
Когда я использую dir для объекта с декораторами @Property getter/setter, он возвращает это общедоступное имя свойства (я понимаю, что эти начальные символы подчеркивания являются просто соглашениями об именах, а не реальными модификаторами доступа). Когда я использую __dict__, он возвращает только частные атрибуты, например. этот объект DatasourceItem имеет такие свойства, как id, которые dir вернет, но __dict__ вернет _id github.com/tableau/server-client-python/blob/master/ - person Davos; 27.03.2018
comment
@Davos: объект property — это объект-дескриптор, который живет в классе, а не в экземпляре. То, что делает средство получения, установки или удаления свойства, полностью зависит от реализации. Свойство может делать все, что угодно, оно вообще ничего не должно делать с экземпляром. dir() в экземпляре по-прежнему будут перечислены любые атрибуты класса и любые атрибуты в экземпляре __dict__, поэтому dir() в экземпляре DatasourceItem будет отображаться как свойство connections, определенное в классе, так и атрибут _connections в экземпляре. пример. - person Martijn Pieters; 27.03.2018
comment
@Davos: так что да, это вполне ожидаемо. Объект DatasourceItem.id property живет в классе, а не в экземпляре. instance.id вызовет метод получения, который затем вернет self._id, где self._id — атрибут экземпляра. - person Martijn Pieters; 27.03.2018
comment
Спасибо за пояснение, оно проясняет для меня ситуацию. Я пытался получить существующий объект источника данных, использовать большинство его атрибутов в новом экземпляре объекта, а затем передать его обратно на сервер для перезаписи. Я подумал, что, возможно, извлечение атрибутов в виде словаря будет немного более динамичным, но простое извлечение значений атрибутов с точечной нотацией, вероятно, лучше с точки зрения кодирования интерфейса, и есть только несколько значений, отличных от значений по умолчанию. Я был ленив и пытался автоматизировать то, что не должно быть. - person Davos; 28.03.2018

Функция f принадлежит словарю класса C. c.__dict__ дает атрибуты, специфичные для экземпляра c.

>>> class C(object):
    def f(self):
        print self.__dict__


>>> c = C()
>>> c.__dict__
{}
>>> c.a = 1
>>> c.__dict__
{'a': 1}

C.__dict__ даст атрибуты класса C, включая функцию f.

>>> C.__dict__
dict_proxy({'__dict__': <attribute '__dict__' of 'C' objects>, '__module__': '__main__', '__weakref__': <attribute '__weakref__' of 'C' objects>, '__doc__': None, 'f': <function f at 0x0313C1F0>})

Хотя объект может ссылаться на атрибут своего класса (да и на все классы-предки), указанный атрибут класса не становится частью самого связанного dict. Таким образом, хотя это законный доступ к функции f, определенной в классе C как c.f(), он не отображается как атрибут c в c.__dict__.

>>> c.a = 1
>>> c.__dict__
{'a': 1}
person Naveen Kumar    schedule 22.01.2016

Классы dir() и dict показывают только определенные функции (методы). Экземпляр dir() показывает данные и методы, а его dict показывает только атрибуты данных, а не методы.

class C2:
...     def __init__(self, id): 
...         self.id = id
...     def set(self, len):
...         self.len = len        
...         
c2 = C2("stick")
dir(C2)
['__class__',.., '__init__', 'set']
dir(c2)
['__class__',.., '__init__', 'id', 'set']
C2.__dict__
mappingproxy({'__init__': <function C2.__init__ at 0x000001899C61E9D0>, 'set': <function C2.set at 0x000001899C61ED30>,...})
c2.__dict__
{'id': 'stick'}
person Leon Chang    schedule 22.06.2021