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}