206 votes

Comment surcharger __getattr__ sans casser le comportement par défaut ?

Comment puis-je remplacer l'option __getattr__ d'une classe sans casser le comportement par défaut ?

20 votes

On demande "rupture", et non "changement". C'est suffisamment clair : les attributs "fantaisie" ne doivent pas interférer avec les attributs intégrés et doivent se comporter autant que possible comme eux. La réponse de Michael est à la fois correcte et utile.

297voto

Michael Williamson Points 6210

Surpassement __getattr__ devrait aller bien __getattr__ n'est appelé qu'en dernier recours, c'est-à-dire si aucun attribut de l'instance ne correspond au nom. Par exemple, si vous accédez à foo.bar alors __getattr__ ne sera appelé que si foo n'a pas d'attribut appelé bar . Si l'attribut est un attribut que vous ne voulez pas gérer, levez AttributeError :

class Foo(object):
    def __getattr__(self, name):
        if some_predicate(name):
            # ...
        else:
            # Default behaviour
            raise AttributeError

Toutefois, à la différence des __getattr__ , __getattribute__ sera appelée en premier (cela ne fonctionne que pour les nouvelles classes de style, c'est-à-dire celles qui héritent de l'objet). Dans ce cas, vous pouvez conserver le comportement par défaut comme suit :

class Foo(object):
    def __getattribute__(self, name):
        if some_predicate(name):
            # ...
        else:
            # Default behaviour
            return object.__getattribute__(self, name)

Voir la documentation Python pour plus d'informations .

0 votes

Bah, votre édition contient la même chose que ce que j'ai montré dans ma réponse, +1.

13 votes

Cool, Python n'a pas l'air d'aimer appeler des super en __getattr__ -- Une idée de ce qu'il faut faire ? ( AttributeError: 'super' object has no attribute '__getattr__' )

1 votes

Sans voir votre code, c'est difficile à dire, mais il semble qu'aucune de vos superclasses ne définisse getattr .

39voto

class A(object):
    def __init__(self):
        self.a = 42

    def __getattr__(self, attr):
        if attr in ["b", "c"]:
            return 42
        raise AttributeError("%r object has no attribute %r" %
                             (self.__class__.__name__, attr))

>>> a = A()
>>> a.a
42
>>> a.b
42
>>> a.missing
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 8, in __getattr__
AttributeError: 'A' object has no attribute 'missing'
>>> hasattr(a, "b")
True
>>> hasattr(a, "missing")
False

23voto

José Luis Points 592

Pour compléter la réponse de Michael, si vous souhaitez conserver le comportement par défaut en utilisant la fonction __getattr__ vous pouvez procéder de la manière suivante :

class Foo(object):
    def __getattr__(self, name):
        if name == 'something':
            return 42

        # Default behaviour
        return self.__getattribute__(name)

Le message d'exception est désormais plus descriptif :

>>> foo.something
42
>>> foo.error
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 5, in __getattr__
AttributeError: 'Foo' object has no attribute 'error'

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X