web-dev-qa-db-fra.com

quelle est la plus grande différence entre dir et __dict__ dans python

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

production:

{}

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

pourquoi il n'y a pas de "f" en soi .__ dict__

60
shellfly

dir() fait bien plus que rechercher __dict__

Tout d'abord, dir() est une méthode API qui sait utiliser des attributs comme __dict__ Pour rechercher les attributs d'un objet.

Cependant, tous les objets n'ont pas d'attribut __dict__. Par exemple, si vous deviez ajouter un __slots__ Attribut à votre classe personnalisée, les instances de cette classe n'auront pas d'attribut __dict__, Pourtant dir() peut toujours répertorier les attributs disponibles sur ces instances:

>>> 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']

La même chose s'applique à de nombreux types intégrés; lists n'ont pas d'attribut __dict__, mais vous pouvez toujours lister tous les attributs à l'aide de 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']

Ce que dir() fait avec les instances

Les instances Python ont leur propre __dict__, Mais leur classe aussi:

>>> 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)]

La méthode dir() utilise les deux ces attributs __dict__, et celui sur object pour créer une liste complète des attributs disponibles sur l'instance, la classe et tous les ancêtres de la classe.

Lorsque vous définissez des attributs sur une classe, les instances les voient également:

>>> 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'

car l'attribut est ajouté à la classe __dict__:

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

Notez comment l'instance __dict__ Est laissée vide. Recherche d'attribut sur les objets Python suit la hiérarchie des objets de l'instance au type aux classes parentes pour rechercher des attributs.

Ce n'est que lorsque vous définissez des attributs directement sur l'instance que vous verrez l'attribut reflété dans le __dict__ De l'instance, tandis que la classe __dict__ Reste inchangée:

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

TLDR; ou le résumé

dir() ne recherche pas seulement le __dict__ d'un objet (qui parfois n'existe même pas), il utilisera l'héritage de l'objet (sa classe ou son type, et toutes les superclasses ou parents, de cette classe ou de ce type) pour vous donner une image complète de tous les attributs disponibles.

Une instance __dict__ Est juste l'ensemble d'attributs "local" sur cette instance et ne contient pas tous les attributs disponibles sur l'instance. Au lieu de cela, vous devez également regarder la classe et l'arbre d'héritage de la classe.

111
Martijn Pieters

La fonction f appartient au dictionnaire de la classe C. c.__dict__ Renvoie des attributs spécifiques à l'instance c.

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


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

C.__dict__ Produirait des attributs de la classe C, y compris la fonction 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>})

Alors qu'un objet peut faire référence à un attribut de sa classe (et en fait à toutes les classes ancêtres), l'attribut de classe ainsi référencé ne fait pas partie du dict lui-même associé. Ainsi, même s'il s'agit d'un accès légitime à la fonction f définie dans la classe C comme c.f(), il n'apparaît pas comme un attribut de c dans c.__dict__.

>>> c.a = 1
>>> c.__dict__
{'a': 1}
5
Naveen Kumar