class C(object):
def f(self):
print self.__dict__
print dir(self)
c = C()
c.f()
выход:
{}
['__class__', '__delattr__','f',....]
почему нет "f" в себе.__ dict__
class C(object):
def f(self):
print self.__dict__
print dir(self)
c = C()
c.f()
выход:
{}
['__class__', '__delattr__','f',....]
почему нет "f" в себе.__ dict__
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']
То же самое относится ко многим встроенным типам; list
не имеют атрибута __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
dir()
не просто ищет объект __dict__
(который иногда даже не существует), он будет использовать наследие объекта (его класс или тип и любые суперклассы или родители этого класса или type), чтобы предоставить вам полную картину всех доступных атрибутов.
Экземпляр __dict__
- это только "локальный" набор атрибутов в этом экземпляре и не содержит всех атрибутов, доступных в экземпляре. Вместо этого вам также нужно посмотреть на класс и наследование наследования классов.
Функция 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}