140 votes

Python - à l'Aide d' __getattribute__ méthode

Je veux l'emporter sur l'accès à une variable dans une classe, mais le retour de tous les autres normalement. Comment puis-je réaliser cela avec __getattribute__?

J'ai essayé le suivant (qui doit aussi illustrer ce que je suis en train de faire), mais je reçois une récursivité d'erreur:

class D(object):
    def __init__(self):
        self.test=20
        self.test2=21
    def __getattribute__(self,name):
        if name=='test':
            return 0.
        else:
            return self.__dict__[name]

>>> print D().test
0.0
>>> print D().test2
...
RuntimeError: maximum recursion depth exceeded in cmp

157voto

Egil Points 2329

Vous obtenez une récursivité erreur parce que vous appelez la même fonction, votre __getattribute__. Si vous utilisez objects' __getattribute__ au lieu de cela, il fonctionne:

class D(object):
    def __init__(self):
        self.test=20
        self.test2=21
    def __getattribute__(self,name):
        if name=='test':
            return 0.
        else:
            return object.__getattribute__(self, name)

Cela fonctionne parce qu' object (dans cet exemple) est la classe de base. En appelant la version de base __getattribute__ vous éviter les récursive de l'enfer vous étiez avant.

Ipython avec le code de sortie foo.py:

In [1]: from foo import *

In [2]: d = D()

In [3]: d.test
Out[3]: 0.0

In [4]: d.test2
Out[4]: 21

Mise à jour:

Il y a quelque chose dans la section intitulée Plus d'attribut d'accès pour les nouveaux-classes de style dans la documentation en cours, où ils recommandent de faire exactement cela pour éviter une récursion infinie.

35voto

tzot Points 32224

En fait, je crois que vous voulez utiliser l' __getattr__ méthode particulière au lieu.

Citation du Python docs:

__getattr__( self, name)

Appelé lorsqu'un attribut de recherche n'a pas trouvé l'attribut dans les endroits habituels (c'est à dire qu'il n'est pas une instance de l'attribut, ni est il a trouvé dans l'arborescence de la classe pour soi). nom est le nom de l'attribut. Cette méthode doit renvoyer le (calculée) valeur de l'attribut ou de soulever une AttributeError exception.
Notez que si l'attribut est trouvé à travers le mécanisme normal, __getattr__() n'est pas appelé. (C'est intentionnel de l'asymétrie entre __getattr__() et __setattr__().) C'est fait à la fois pour des raisons d'efficacité et parce que, sinon, __setattr__() n'ont aucun moyen d'accéder à d'autres attributs de l'instance. Notez que, au moins pour les variables d'instance, vous pouvez faux contrôle total par pas d'insérer des valeurs dans l'instance de l'attribut dictionnaire (mais au lieu de les insérer dans un autre objet). Voir l' __getattribute__() méthode ci-dessous pour un moyen d'obtenir un contrôle total de new-classes de style.

Note: pour que cela fonctionne, l'instance devrait pas avoir un test d'attribut, de sorte que la ligne self.test=20 doit être supprimé.

21voto

ttepasse Points 372

Référence au langage Python:

Afin d'éviter une récursion infinie dans cette méthode, sa mise en œuvre devrait toujours faire appel à la classe de base méthode avec le même nom pour accéder à tous les attributs dont il a besoin, par exemple, objet.getattribute(self, nom).

Sens:

def __getattribute__(self,name):
    ...
        return self.__dict__[name]

Vous appelez pour un attribut appelé __dict__. Parce que c'est un attribut __getattribute__ obtenir ce qu'on appelle dans la recherche d' __dict__ qui demande __getattribute__ qui appelle ... et patati et patata

return  object.__getattribute__(self, name)

En utilisant les classes de base __getattribute__ aide à trouver le véritable attribut.

13voto

Singletoned Points 2652

Êtes-vous sûr que vous voulez utiliser getattribute? De quoi êtes-vous en train d'essayer de réaliser?

La façon la plus simple de faire ce que vous demandez est:

class D(object):
    def __init__(self):
        self.test = 20
        self.test2 = 21

    test = 0

ou:

class D(object):
    def __init__(self):
        self.test = 20
        self.test2 = 21

    @property
    def test(self):
        return 0

Edit: Notez qu'une instance de D aurait différentes valeurs de test dans chaque cas. Dans le premier cas d.test serait de 20, dans le second, elle sera de 0. Je vais le laisser à vous de savoir pourquoi.

Edit2: Greg a souligné que l'exemple 2 va échouer parce que la propriété est en lecture seule et l' __init__ méthode essayé de le mettre à 20. Un exemple plus complet pour ce qui serait:

class D(object):
    def __init__(self):
        self.test = 20
        self.test2 = 21

    _test = 0

    def get_test(self):
        return self._test

    def set_test(self, value):
        self._test = value

    test = property(get_test, set_test)

Évidemment, en tant que classe, c'est presque tout à fait inutile, mais ça vous donne une idée de déplacer sur de.

5voto

ElmoVanKielmo Points 3562

Voici un moyen plus fiable de la version:

class D(object):
    def __init__(self):
        self.test = 20
        self.test2 = 21
    def __getattribute__(self, name):
        if name == 'test':
            return 0.
        else:
            return super(D, self).__getattribute__(name)

Il appelle __getattribute__ méthode de classe parent, finalement tomber vers l'objet.__getattribute__ méthode si d'autres ancêtres de ne pas le remplacer.

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