2010-08-05 16 views
7

esta es la primera vez que escribo aquí, disculpe si el mensaje es imprevisto o demasiado largo.Comportamiento asimétrico para __getattr__, newstyle vs oldstyle classes

Estaba interesado en comprender más acerca de cómo se obtienen los atributos de los objetos cuando sea necesario. Así que leí la documentación de Python 2.7 titulada "Modelo de datos" here, me encontré con __getattr__ y, para verificar si entendí o no su comportamiento, escribí estas envolturas de cadena simples (e incompletas).

class OldStr: 
    def __init__(self,val): 
    self.field=val 

    def __getattr__(self,name): 
    print "method __getattr__, attribute requested "+name 

class NewStr(object): 
    def __init__(self,val): 
    self.field=val 

    def __getattr__(self,name): 
    print "method __getattr__, attribute requested "+name 

Como puede ver, son las mismas excepto por ser una clase oldstyle vs newstyle. Dado que el texto citado dice __getattr__ es "Llamado cuando una búsqueda de atributo no ha encontrado el atributo en los lugares habituales", quería probar una operación + en dos instancias de esas clases para ver qué sucedía, esperando un comportamiento idéntico.

Pero los resultados que me hizo un poco de desconcierto:

>>> x=OldStr("test") 
>>> x+x 
method __getattr__, attribute requested __coerce__ 
Traceback (most recent call last): 
File "<stdin>", line 1, in <module> 
TypeError: 'NoneType' object is not callable 

bueno! No definí un método para __coerce__ (aunque esperaba una solicitud de __add__, no importa :), entonces __getattr__ se involucró y devolvió una cosa inútil. Pero entonces

>>> y=NewStr("test") 
>>> y+y 
Traceback (most recent call last): 
File "<stdin>", line 1, in <module> 
TypeError: unsupported operand type(s) for +: 'NewStr' and 'NewStr' 

¿Por qué este comportamiento asimétrico entre __getattr__ en las clases de estilo antiguo y los newstyle cuando se utiliza un operador incorporado como +? ¿Podría alguien ayudarme a entender qué está pasando y cuál fue mi error al leer la documentación?

Muchas gracias, su ayuda es muy apreciada!

+6

No use clases de estilo antiguo para nada. Están obsoletos por razones obvias, como esta. Ya que están en desuso, saber cómo solían trabajar no es útil. Deséchelos y continúe, por favor. –

+3

La comparación del comportamiento de las clases antiguas y nuevas ayuda a ilustrar cómo funcionan las clases de estilo nuevo, especialmente si está familiarizado con las clases antiguas. De hecho, no es de extrañar que funcionen de diferentes maneras, y es reconfortante saber que las nuevas clases funcionan como se esperaba. Aún así, es valioso tratar de entender por qué el código se interpreta de la manera en que lo hace, sin importar la versión. –

Respuesta

2

Sus funciones __getattr__ no devuelven nada. No sé por qué la clase de estilo antiguo está haciendo el __getattr__ antes de buscar __add__, pero lo es, y esto está intentando llamar al valor de retorno que es None.

La clase de nuevo estilo lo está haciendo bien: no ha definido __add__ por lo que no sabe cómo agregarlos.

4

Ver Special method lookup for new-style classes.

Los métodos especiales se buscan directamente en el objeto de clase, los objetos de instancia y, por consiguiente, __getattr__() y __getattribute__() se pasan por alto. Por precisamente la misma razón, instance.__add__ = foobar no funciona.

Esto se hace para acelerar el acceso de los atributos. Los métodos especiales se llaman con mucha frecuencia, y hacerlos sujetos a la búsqueda de atributos estándar y bastante complejos ralentizaría significativamente al intérprete.

La búsqueda de atributos para clases antiguas es mucho menos compleja (más notablemente las clases antiguas no admiten descriptores), por lo que no hay ninguna razón para tratar los métodos especiales de forma diferente en las clases antiguas.

Cuestiones relacionadas