2010-08-05 3 views
7

C'est la première fois que j'écris ici, désolé si le message est non traité ou trop long.Comportement asymétrique pour les classes __getattr__, newstyle vs oldstyle

Je voulais en savoir plus sur la façon dont les attributs d'objets sont récupérés en cas de besoin. J'ai donc lu la documentation Python 2.7 intitulée "Data Model" here, j'ai rencontré __getattr__ et, afin de vérifier si je comprenais ou non son comportement, j'ai écrit ces wrappers de chaînes simples (et incomplètes).

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 

Comme vous pouvez le voir, ils sont identiques à l'exception des classes oldstyle et newstyle. Puisque le texte cité dit __getattr__ est "Appelé lorsqu'une recherche d'attribut n'a pas trouvé l'attribut aux endroits habituels", j'ai voulu essayer une opération + sur deux instances de ces classes pour voir ce qui s'est passé, s'attendant à un comportement identique.

Mais les résultats que je me suis un peu perplexe:

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

Bon! Je n'ai pas défini une méthode pour __coerce__ (bien que j'attendais une demande pour __add__, nevermind :), donc __getattr__ s'est impliqué et a retourné une chose inutile. Mais

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

Pourquoi ce comportement asymétrique entre __getattr__ dans les classes et les oldstyle Newstyle lors de l'utilisation d'un opérateur intégré comme +? Quelqu'un pourrait-il m'aider s'il vous plaît à comprendre ce qui se passe, et quelle a été mon erreur en lisant la documentation?

Merci beaucoup, votre aide est fortement appréciée!

+6

Veuillez ne pas utiliser de classes de style ancien pour quelque chose. Ils sont dépréciés pour des raisons évidentes - comme celui-ci. Depuis qu'ils sont obsolètes, sachant comment ils ont l'habitude de travailler n'est pas utile. Jetez-les et continuez, s'il vous plaît. –

+3

La comparaison du comportement des classes anciennes et nouvelles aide à illustrer le fonctionnement des classes de style nouveau, en particulier si vous connaissez les classes de style ancien. Il n'est en effet pas surprenant qu'ils travaillent de différentes manières, et il est réconfortant de savoir que les nouvelles classes fonctionnent comme prévu. Pourtant, il est utile d'essayer de comprendre pourquoi le code est interprété comme il est, peu importe la version. –

Répondre

2

Vos fonctions __getattr__ ne retournent rien. Je ne sais pas pourquoi la classe old-style fait le __getattr__ avant de chercher __add__, mais il est, et cela essaie d'appeler la valeur de retour qui est None.

La nouvelle classe de style va bien: vous n'avez pas défini __add__ donc elle ne sait pas comment les ajouter.

4

Voir Special method lookup for new-style classes.

Les méthodes spéciales sont directement recherchées dans l'objet de classe, les objets d'instance et, par conséquent, __getattr__() et __getattribute__() sont ignorés. Pour exactement la même raison, instance.__add__ = foobar ne fonctionne pas.

Ceci est fait pour accélérer l'accès aux attributs. Les méthodes spéciales sont appelées très fréquemment, et en les soumettant à la recherche d'attributs standard plutôt complexe, cela ralentirait considérablement l'interprète.

La recherche d'attribut pour les classes de style ancien est beaucoup moins complexe (notamment les anciennes classes de style ne supportant pas les descripteurs), il n'y a donc aucune raison de traiter les méthodes spéciales différemment dans les classes de style ancien.

Questions connexes