如何在python中捕获对对象调用的任何方法?
我正在寻找一个pythonic解决方案,该解决方案涉及如何在对象内部存储对对象调用的方法 因为在python中,如果我想捕获例如如何在python中捕获对对象调用的任何方法?,python,oop,object,methods,call,Python,Oop,Object,Methods,Call,我正在寻找一个pythonic解决方案,该解决方案涉及如何在对象内部存储对对象调用的方法 因为在python中,如果我想捕获例如abs()方法,我将重载此操作符,如下所示: Catcher(object): def __abs__(self): self.function = abs c = Catcher() abs(c) # Now c.function stores 'abs' as it was called on c 如果我想捕获一个函数,其中包含其他属性
abs()
方法,我将重载此操作符,如下所示:
Catcher(object):
def __abs__(self):
self.function = abs
c = Catcher()
abs(c) # Now c.function stores 'abs' as it was called on c
如果我想捕获一个函数,其中包含其他属性,例如pow()
,我将使用以下方法:
Catcher(object):
def __pow__(self, value):
self.function = pow
self.value = value
c = Catcher()
c ** 2 # Now c.function stores 'pow', and c.value stores '2'
现在,我要寻找的是一个通用的解决方案,捕获并存储在Catcher
上调用的任何类型的函数,而不实现所有重载和其他情况。正如您所看到的,我还想存储值(可能在列表中,如果有多个值?),这些值是方法的属性
提前谢谢 元类在这里没有帮助;尽管在当前对象的类型上查找特殊方法(因此实例的类),但在执行此操作时,不会参考
\uuuuu getattribute\uuuuu
或\uuuuuuu getattr\uuuuu
(可能是因为它们本身就是特殊方法)。因此,为了捕获所有dunder方法,您必须创建它们
通过列举以下内容,您可以获得所有运算符特殊方法(\uuuu pow\uuuu
,\uu gt\uuuu
等)的一个相当不错的列表:
使用该列表,类装饰器可以是:
def instrument_operator_hooks(cls):
def add_hook(name):
operator_func = getattr(operator, name.strip('_'), None)
existing = getattr(cls, name, None)
def op_hook(self, *args, **kw):
print "Hooking into {}".format(name)
self._function = operator_func
self._params = (args, kw)
if existing is not None:
return existing(self, *args, **kw)
raise AttributeError(name)
try:
setattr(cls, name, op_hook)
except (AttributeError, TypeError):
pass # skip __name__ and __doc__ and the like
for hook_name in operator_hooks:
add_hook(hook_name)
return cls
然后将其应用于您的班级:
@instrument_operator_hooks
class CatchAll(object):
pass
演示:
>c=CatchAll()
>>>c**2
与战俘挂钩__
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
文件“”,第11行,在op_hook中
属性错误:uuu pow__
>>>c._函数
>>>c.(u参数)
((2,), {})
因此,即使我们的类没有明确定义
\uuuupow\uuuuuu
,我们仍然与之挂钩。这是一种方法
import inspect
from functools import wraps
from collections import namedtuple
call = namedtuple('Call', ['fname', 'args', 'kwargs'])
calls = []
def register_calls(f):
@wraps(f)
def f_call(*args, **kw):
calls.append(call(f.__name__, args, kw))
print calls
return f(*args, **kw)
return f_call
def decorate_methods(decorator):
def class_decorator(cls):
for name, m in inspect.getmembers(cls, inspect.ismethod):
setattr(cls, name, decorator(m))
return cls
return class_decorator
@decorate_methods(register_calls)
class Test(object):
def test1(self):
print 'test1'
def test2(self):
print 'test2'
现在,对test1
和test2
的所有调用都将在调用
列表中注册
decoration\u方法
对类的每个方法应用一个decoratorregister\u调用
使用函数名和参数注册对调用
中的方法的调用 对于不委托给dunder方法的函数呢?您可能需要研究类装饰器和元类。@delnan我想,这些也可以,因为在我的例子中,这些函数正在寻找其他东西,一个值或一个方法来调用。@morphyn您能更具体一点吗?AFAIK元类对类对象的创建很好,不是吗?@poorsod:不,我试过那种方法。Dunder钩子是在类而不是实例上查找的,因此需要一个元类。但是\uuuu getattr\uuuu
似乎不用于这种情况。\uuuu getattribute\uuuu
也不例外。但这仍然要求您首先在类上创建所有特殊方法。@morphyn是的,Martijn Pieters是对的,我刚刚测试了这个-也许我没有正确使用它-但我不能用它做我想做的事情…是的,您仍然需要创建这些方法。我不明白你想要什么。你正在寻找ruby的方法\u missing
然后:)你将不得不使用\uu getattr\uuu
然后。因为我对@decorators
非常陌生,我不得不读这篇文章,它非常简单,然后我才明白你做了什么。。我必须承认,现在我知道发生了什么-这不再是一种魔法:):)我在一个decorator类中重新实现了你的解决方案-我想,更容易理解代码中的内容。@PeterVaro:那很好。:-)我回答的重点是如何生成dunder方法名称列表:-P
>>> c = CatchAll()
>>> c ** 2
Hooking into __pow__
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 11, in op_hook
AttributeError: __pow__
>>> c._function
<built-in function pow>
>>> c._params
((2,), {})
import inspect
from functools import wraps
from collections import namedtuple
call = namedtuple('Call', ['fname', 'args', 'kwargs'])
calls = []
def register_calls(f):
@wraps(f)
def f_call(*args, **kw):
calls.append(call(f.__name__, args, kw))
print calls
return f(*args, **kw)
return f_call
def decorate_methods(decorator):
def class_decorator(cls):
for name, m in inspect.getmembers(cls, inspect.ismethod):
setattr(cls, name, decorator(m))
return cls
return class_decorator
@decorate_methods(register_calls)
class Test(object):
def test1(self):
print 'test1'
def test2(self):
print 'test2'