dunder data builtins __dict__ python introspection

data - models python



¿Cuál es la mayor diferencia entre dir y__dict__ en python? (2)

dir() hace mucho más que buscar __dict__

En primer lugar, dir() es un método API que sabe cómo usar atributos como __dict__ para buscar los atributos de un objeto.

Sin embargo, no todos los objetos tienen un atributo __dict__ . Por ejemplo, si agregara un atributo __slots__ a su clase personalizada, las instancias de esa clase no tendrán un atributo __dict__ , sin embargo, dir() aún puede enumerar los atributos disponibles en esas instancias:

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

Lo mismo se aplica a muchos tipos incorporados; list s no tiene un atributo __dict__ , pero aún puede enumerar todos los atributos usando 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'']

Lo que dir() hace con las instancias.

Las instancias de Python tienen su propio __dict__ , pero también lo tiene su clase:

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

El método dir() utiliza estos atributos __dict__ y el object on para crear una lista completa de los atributos disponibles en la instancia, la clase y en todos los ancestros de la clase.

Cuando establece atributos en una clase, las instancias también las ven:

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

porque el atributo se agrega a la clase __dict__ :

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

Observe cómo la instancia __dict__ se deja vacía. La búsqueda de atributos en objetos de Python sigue la jerarquía de objetos desde la instancia hasta el tipo y las clases primarias para buscar atributos.

Solo cuando establezca atributos directamente en la instancia, verá el atributo reflejado en el __dict__ de la instancia, mientras que la clase __dict__ se modifica:

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

TLDR; o el resumen

dir() no solo busca el __dict__ un objeto (que a veces ni siquiera existe), utilizará el patrimonio del objeto (su clase o tipo y las superclases o padres de esa clase o tipo) para brindarle Una imagen completa de todos los atributos disponibles.

Una instancia __dict__ es solo el conjunto de atributos ''local'' en esa instancia, y no contiene todos los atributos disponibles en la instancia. En su lugar, también debe mirar la clase y el árbol de herencia de la clase.

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

salida:

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

por qué no hay una ''f'' en sí mismo .__ dict__


La función f pertenece al diccionario de la clase C c.__dict__ produce atributos específicos de la instancia c .

>>> class C(object): def f(self): print self.__dict__ >>> c = C() >>> c.__dict__ {} >>> c.a = 1 >>> c.__dict__ {''a'': 1}

C.__dict__ daría atributos de clase C , incluida la función 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>})

Mientras que un objeto puede referirse a un atributo de su clase (y de hecho a todas las clases ancestrales), el atributo de clase así referido no se convierte en parte del dictado asociado en sí. Por lo tanto, si bien es un acceso legítimo a la función f definida en la clase C como cf() , no aparece como un atributo de c en c.__dict__ .

>>> c.a = 1 >>> c.__dict__ {''a'': 1}