如何捕捉叫Python中的对象上的任何方法?(How to catch any method cal

2019-09-01 23:02发布

我在寻找如何存储被称为对象的权利对象内部的方法的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 ,而不实现所有的过载,和其他案件。 正如你所看到的,我也想存储的值( 也许在列表中,如果有超过其中一个?),这是一个方法的属性。

提前致谢!

Answer 1:

一个元将不会在​​这里帮助; 虽然特殊的方法查找在当前对象(所以类实例),类型__getattribute____getattr__这样做(可能是因为他们本身就是特殊的方法)时,不协商。 因此,要捕捉所有 dunder方法,你不得不创造它们。

你可以得到的所有操作员的专用方法(一个相当不错的列表__pow____gt__等)通过枚举operator模块 :

import operator
operator_hooks = [name for name in dir(operator) if name.startswith('__') and name.endswith('__')]

武装与列表中的类装饰可以是:

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
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,), {})

所以,尽管我们班没有定义__pow__明确,我们还是迷上了进去。



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

现在所有的调用test1test2将在寄存器calls list

decorate_methods施加装饰器类的每个方法。 register_calls登记在方法的调用, calls ,具有的功能和参数的名称。



文章来源: How to catch any method called on an object in python?