似乎__getattribute__
只有 2 个参数(self, name)
。
但是,在实际代码中,我拦截的方法实际上是带参数的。
无论如何可以访问这些论点吗?
谢谢,
查理
似乎__getattribute__
只有 2 个参数(self, name)
。
但是,在实际代码中,我拦截的方法实际上是带参数的。
无论如何可以访问这些论点吗?
谢谢,
查理
__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)
Python中的方法调用是两步过程,首先查找一个函数,然后调用它。有关更复杂的讨论,请参阅我对这个问题的回答。
所以你需要做这样的事情:
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__ 不足以满足您的目的吗?或者甚至可能是一个返回函数的描述符对象。描述符通常更擅长重用。
这是 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在使用__getattribute__
. 它被 上的所有属性查找调用self
,甚至是__getattribute__
方法内部的那些。其他几个示例包括对self.__dict__
inside 的引用,__getattribute__
这将导致递归,直到超过最大堆栈深度!__getattribute__
为避免这种情况,请使用(例如object.__getattribute__(self,name)
.)的基类版本之一
老实说,我不确定我是否理解你的问题。如果您想要一种方法来覆盖 getattribute 并保留您可以使用的原始属性__dict__
def __getattribute__(self, attr):
if attr in self.__dict__:
return self.__dict__[attr]
# Add your changes here
我不认为你可以。__getattribute__
不拦截方法调用,只拦截方法名查找。所以它应该返回一个函数(或可调用对象),然后将使用调用站点指定的任何参数调用该函数。
特别是,如果它返回一个接受 的函数(*args, **kwargs)
,那么在该函数中,您可以根据需要检查参数。
我认为。我不是 Python 专家。
是的
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
感谢ASk的 回答(非常感谢您的朋友)我设法解决了我的问题,但是我不得不更换
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...'