2012-06-26 5 views
24

cuando digo "atributo pitón de búsqueda proccess" quiero decir: ¿qué pitón hace cuando se escribe x.foo ??¿Cómo funciona el proceso de búsqueda de atributos python?

Buscando en la web y no encontré a mucha documentación acerca de esto, uno de los mejores papeles que encontré reanudó la proccess a los siguientes pasos (se puede ver el artículo completo here)

  1. Si es attrname un atributo especial (es decir, Python-provided) para objectname, lo devuelve.
  2. Comprobar objectname .__ clase __.__ dict__ para attrname. Si existe y es un descriptor de datos, devuelva el resultado del descriptor. Buscar todas las bases de objectname .__ class__ para el mismo caso.
  3. Comprobar objectname .__ dict__ para attrname, y volver si se encuentra. Si objectname es una clase, busca sus bases también. Si es una clase y existe un descriptor en ella o sus bases, devuelva el resultado del descriptor.
  4. Comprobar objectname .__ clase __.__ dict__ para attrname. Si existe y no es un descriptor de datos, devuelva el resultado del descriptor. Si existe, y no es un descriptor, simplemente devuélvalo. Si existe y es un descriptor de datos, no deberíamos estar aquí porque hubiéramos regresado en el punto 2. Buscar todas las bases de objectname .__ class__ para el mismo caso.
  5. Elevar AttributeError.

Al principio esto puede parecer correcto, pero el proceso de búsqueda de atributos es un poco más complicado, por ejemplo para x.foo, no se comporta igual si x es una clase o una instancia.

he encontrado un algunas muestras que no pueden ser explicados por este camino. Considere el siguiente código Python:

class Meta(type): 
    def __getattribute__(self, name): 
     print("Metaclass getattribute invoked:", self) 
     return type.__getattribute__(self, name) 

    def __getattr__(self, item): 
     print('Metaclass getattr invoked: ', item) 
     return None 

class C(object, metaclass=Meta): 
    def __getattribute__(self, name): 
     print("Class getattribute invoked:", args) 
     return object.__getattribute__(self, name) 

c=C() 

Ahora compruebe las siguientes líneas con la salida correspondiente:

>> C.__new__ 
Metaclass getattribute invoked: <class '__main__.C'> 
<built-in method __new__ of type object at 0x1E1B80B0> 

>> C.__getattribute__ 
Metaclass getattribute invoked: <class '__main__.C'> 
<function __getattribute__ at 0x01457F18> 

>> C.xyz 
Metaclass getattribute invoked: <class '__main__.C'> 
Metaclass getattr invoked: xyz 
None 

>> c.__new__ 
Class getattribute invoked: (<__main__.C object at 0x013E7550>, '__new__') 
<built-in method __new__ of type object at 0x1E1B80B0> 

>> c.__getattribute__ 
Class getattribute invoked: (<__main__.C object at 0x01438DB0>, '__getattribute__') 
Metaclass getattribute invoked: <class '__main__.C'> 
<bound method C.__getattribute__ of <__main__.C object at 0x01438DB0>> 

>> 

Las conclusiones son que he estado (teniendo en cuenta que estamos buscando x.foo):

  • __getattribute__ es diferente para las instancias de < tipo 'tipo'> y < tipo 'objeto'>. Para C.foo(), 'foo' se busca primero en C .__ dict__ y se devuelve si se encuentra (en lugar del tipo de búsqueda (C)) y para x.foo() 'foo' se busca en tipo (x) .__ dict__ y en x .__ dict__.
  • __getattribute__ método siempre se resuelve en el tipo (x), lo que no entiendo aquí es el último caso: c .__ getattribute__, no es objeto contiene un método __getattribute__ (y C hereda del objeto), entonces ¿por qué metaclass El método getattribute se llama.

Puede alguien explicar esto, por favor ?? o al menos dime dónde puedo encontrar documentación sobre esto, gracias.

Respuesta

4

Si ha añadido print("Metaclass getattribute invoked:", self, name) verías:

>>> c.__getattribute__ 
Class getattribute invoked: <__main__.C object at 0x2acdbb1430d0> __getattribute__ 
Metaclass getattribute invoked: <class '__main__.C'> __name__ 
<bound method C.__getattribute__ of <__main__.C object at 0x2acdbb1430d0>> 

La metaclase __getattribute__ está siendo invocado con el fin de construir el repr de la expresión c.__getattribute__, para que se pueda imprimir C 's __name__.

por cierto, __getattribute__ funciona igual para clases y metaclasses; el atributo se busca primero en la instancia y luego en el tipo de instancia.

>>> Meta.foo = 1 
>>> C.foo 
('Metaclass getattribute invoked:', <class '__main__.C'>, 'foo') 
1 
>>> c.foo 
('Class getattribute invoked:', <__main__.C object at 0x2acdbb1430d0>, 'foo') 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<stdin>", line 5, in __getattribute__ 
AttributeError: 'C' object has no attribute 'foo' 
>>> C.bar = 2 
>>> c.bar 
('Class getattribute invoked:', <__main__.C object at 0x2acdbb1430d0>, 'bar') 
2 
+2

Tipos y objetos de Python http://www.cafepy.com/article/python_types_and_objects/ – amirouche

Cuestiones relacionadas