2009-05-26 2 views

Répondre

1

Honnêtement, je ne suis pas sûr que je comprends votre question. Si vous voulez un moyen de passer outre getattribute et pourtant conserver les attributs d'origine, vous pouvez utiliser __dict__

def __getattribute__(self, attr): 
    if attr in self.__dict__: 
      return self.__dict__[attr] 
    # Add your changes here 
3

invocation de la méthode en Python est procédé à deux étapes, la première fonction est recherchée, il est invoqué. Pour une discussion plus détaillée voir ma réponse au this question.

Donc, vous devez faire quelque chose comme ceci:

def __getattribute__(self, key): 
    if key == "something_interesting": 
     def func(*args, **kwargs): 
      # use arguments, and possibly the self variable from outer scope 
     return func 
    else: 
     return object.__getattribute__(self, key) 

En outre, outrepassant __getattribute__ est généralement une mauvaise idée. Parce qu'il est appelé sur tous les accès aux attributs, il est vraiment facile de se retrouver dans une boucle infinie, et même si vous faites tout correctement, cela finit par être un gros succès. Etes-vous sûr que __getattr__ ne suffira pas à vos besoins? Ou peut-être même un objet descripteur qui retourne des fonctions. Les descripteurs sont généralement beaucoup mieux à réutiliser.

+0

je reçois l'argument hors de portée lorsque je tente d'utiliser les arguments (par exemple: arg [1] est le premier paramètre, arg [2] est le deuxième, etc ... –

+0

jamais l'esprit. Cela fonctionne parfaitement. Je dois avoir tapé quelque chose de mal. Merci beaucoup. –

5

__getattribute__ retourne simplement l'attribut qui a été demandé, dans le cas d'une méthode, l'interface __call__ est ensuite utilisé pour appeler.

au lieu de retourner la méthode, le retour d'une enveloppe autour d'elle, par exemple:

def __getattribute__(self, attr): 
    def make_interceptor(callble): 
     def func(*args, **kwargs): 
      print args, kwargs 
      return callble(*args, **kwargs) 
     return func 
    att = self.__dict__[attr] 
    if callable(att): 
     return make_interceptor(att) 
1

Je ne pense pas que vous pouvez. __getattribute__ n'intercepte pas l'appel de méthode, il n'intercepte que la recherche de nom de méthode. Il devrait donc renvoyer une fonction (ou objet appelable), qui sera appelée avec tous les paramètres spécifiés sur le site d'appel.

En particulier, si elle renvoie une fonction qui prend (*args, **kwargs), alors dans cette fonction vous pouvez examiner les arguments comme vous le souhaitez.

Je pense. Je ne suis pas un expert Python.

0

Oui

def argumentViewer(func): 
    def newfunc(*args, **kwargs): 
     print "Calling %r with %r %r" % (func, args, kwargs) 
     return func(*args, **kwargs) 
    return newfunc 

class Foo(object): 
    def __getattribute__(self, name): 
     print "retrieving data" 
     return object.__getattribute__(self, name) 

    @argumentViewer 
    def bar(self, a, b): 
     return a+b 

# Output 
>>> a=Foo() 
>>> a.bar 
retrieving data 
<bound method Foo.newfunc of <__main__.Foo object at 0x01B0E3D0>> 
>>> a.bar(2,5) 
retrieving data 
Calling <function bar at 0x01B0ACF0> with (<__main__.Foo object at 0x01B0E3D0>, 2, 5) {} 
7 
+0

Cela "fonctionne" alors merci. Mais ce n'est pas exactement ce que j'espérais. Cela impliquerait moi de modifier la sous-classe avec "def bar" le __getattribute__ vit dans la classe de base et je voudrais être en mesure de créer cette fonctionnalité sans changer la classe dérivée. –

1

Voici une variation sur la suggestion de Unknown qui renvoie une instance appelable "wrapper" à la place de la fonction demandée. Cela ne nécessite pas la décoration de toutes les méthodes:

class F(object): 
    def __init__(self, func): 
     self.func = func 
     return 
    def __call__(self, *args, **kw): 
     print "Calling %r:" % self.func 
     print " args: %r" % (args,) 
     print " kw: %r" % kw 
     return self.func(*args,**kw) 

class C(object): 
    def __init__(self): 
     self.a = 'an attribute that is not callable.' 
     return 
    def __getattribute__(self,name): 
     attr = object.__getattribute__(self,name) 
     if callable(attr): 
     # Return a callable object that can examine, and even 
     # modify the arguments prior to calling the method. 
     return F(attr) 
     # Return the reference to any non-callable attribute. 
     return attr 
    def m(self, *a, **kw): 
     print "hello from m!" 
     return 

>>> c=C() 
>>> c.a 
'an attribute that is not callable.' 
>>> c.m 
<__main__.F object at 0x63ff30> 
>>> c.m(1,2,y=25,z=26) 
Calling <bound method C.m of <__main__.C object at 0x63fe90>>: 
    args: (1, 2) 
    kw: {'y': 25, 'z': 26} 
hello from m! 
>>> 

Ants Aasma above fait un point important en ce qui concerne la récursivité lors de l'utilisation __getattribute__. Il est appelé par toutes les recherches d'attribut sur self, même ceux à l'intérieur de la méthode __getattribute__.Plusieurs des autres exemples incluent des références à self.__dict__ à l'intérieur de __getattribute__ qui entraîneront un récursif jusqu'à ce que vous dépassiez la profondeur de pile maximale! Pour éviter cela, utilisez une des versions de la classe de base de __getattribute__ (par exemple object.__getattribute__(self,name).)

0

Merci à ASkanswer (grand merci mon pote) j'ai réussi à résoudre mon problème, mais je devais remplacer

 att = self.__dict__[attr] 

avec

att = type(self).__dict__[attr].__get__(self, type(self)) 

et ici travaille par exemple avec décorateur de classe:

def getattribute(self, name): 
    if name.startswith('__') and name.endswith('__'): 
     return object.__getattribute__(self, name) 
    s = '*** method "%s" of instance "%s" of class "%s" called with'\ 
     ' following' 
    print s % (name, id(self), self.__class__.__name__), 

    def intercept(call, name): 
     def func(*args, **kwargs): 
      print 'args: {}, kwargs: {} ***'.format(args, kwargs) 
      c = call(*args, **kwargs) 
      print '*** "%s" finished ***' % name 
      return c 
     return func 
    a = type(self).__dict__[name].__get__(self, type(self)) 
    if callable(a): 
     return intercept(a, name) 
    return object.__getattribute__(self, name) 


def inject(cls): 
    setattr(cls, '__getattribute__', getattribute) 
    return cls 


@inject 
class My_Str(object): 
    def qwer(self, word='qwer'): 
     print 'qwer done something here...' 
Questions connexes