如果你实现 __getattribute__ 有没有办法访问形式参数

Posted

技术标签:

【中文标题】如果你实现 __getattribute__ 有没有办法访问形式参数【英文标题】:Is there a way to access the formal parameters if you implement __getattribute__ 【发布时间】:2010-10-29 01:18:43 【问题描述】:

好像__getattribute__ 只有两个参数(self, name)

但是,在实际代码中,我拦截的方法实际上是带参数的。

有没有办法访问这些参数?

谢谢,

查理

【问题讨论】:

【参考方案1】:

老实说,我不确定我是否理解您的问题。如果您想要一种覆盖 getattribute 并保留原始属性的方法,您可以使用 __dict__

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

【讨论】:

【参考方案2】:

Python中的方法调用是两步过程,首先查找一个函数,然后调用它。如需更深入的讨论,请参阅我对this question 的回答。

所以你需要做这样的事情:

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)

另外,覆盖 __getattribute__ 通常是个坏主意。因为它在所有属性访问上都被调用,所以很容易陷入无限循环,即使你做的一切正确,它最终也会对性能造成很大的影响。您确定 __getattr__ 不足以满足您的目的吗?或者甚至可能是一个返回函数的描述符对象。描述符通常更擅长重用。

【讨论】:

当我尝试使用参数时,参数超出范围(即:arg[1] 是第一个参数,arg[2] 是第二个参数,等等...... 没关系。这完美地工作。我一定是打错了。非常感谢。【参考方案3】:

__getattribute__ 只返回请求的属性,如果是方法,则使用 __call__ 接口调用它。

不是返回方法,而是返回一个包装器,例如:

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)

【讨论】:

【参考方案4】:

我不认为你可以。 __getattribute__ 不拦截方法调用,只拦截方法名查找。所以它应该返回一个函数(或可调用对象),然后将使用调用站点指定的任何参数调用该函数。

特别是,如果它返回一个接受(*args, **kwargs) 的函数,那么在该函数中,您可以根据需要检查参数。

我想。我不是 Python 专家。

【讨论】:

【参考方案5】:

是的

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

【讨论】:

这个“有效”,所以谢谢。但这并不是我所希望的。这将涉及我使用“def bar”修改子类,getattribute 存在于基类中,我希望能够在不更改派生类的情况下创建此功能。【参考方案6】:

这里是 Unknown 建议的一个变体,它返回一个可调用的“包装器”实例来代替请求的函数。这不需要装饰任何方法:

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 在使用__getattribute__ 时对递归提出了重要的一点。它由self 上的all 属性查找调用,甚至是__getattribute__ 方法内部的那些查找。其他几个示例包括在__getattribute__ 内部对self.__dict__ 的引用,这将导致递归,直到超过最大堆栈深度!为避免这种情况,请使用其中一种 __getattribute__ 的基类版本(例如object.__getattribute__(self,name)。)

【讨论】:

【参考方案7】:

感谢ASk answer(非常感谢您的朋友)我设法解决了我的问题,但是我不得不更换

     att = self.__dict__[attr]

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

这是使用类装饰器的工作示例:

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

【讨论】:

以上是关于如果你实现 __getattribute__ 有没有办法访问形式参数的主要内容,如果未能解决你的问题,请参考以下文章

Python魔法方法(11):__getattribute __(self, item) 方法

为覆盖了 __getattribute__ 的类实现 __del__ 方法

python元编程之使用动态属性实现定制类--特殊方法__setattr__,__getattribute__篇

Python-魔法函数__getattr__()与__getattribute__()的区别

Python的__getattr__和__getattribute__

`__getattribute__` 和 `__getattr__` 中的错误处理