Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/351.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在python中捕获对对象调用的任何方法?_Python_Oop_Object_Methods_Call - Fatal编程技术网

如何在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 如果我想捕获一个函数,其中包含其他属性

我正在寻找一个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
如果我想捕获一个函数,其中包含其他属性,例如
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方法
对类的每个方法应用一个decorator
register\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'