响应所有方法调用的Python类实例

Sal*_*alo 10 python

有没有办法创建一个实例响应任意方法调用的类?

我知道__getattr__(self, attr)当有人试图访问实例的属性时会有一个特殊的方法被调用.我正在寻找类似的东西,使我能够拦截方法调用.期望的行为看起来像这样:

class A(object):
    def __methodintercept__(self, method, *args, **kwargs): # is there a special method like this??
        print(str(method))


>>> a = A()
>>> a.foomatic()
foomatic
Run Code Online (Sandbox Code Playgroud)

编辑

其他建议的问题没有解决我的情况:我不想包装另一个类或更改第二类或类似的元类.我只想拥有一个响应任意方法调用的类.

感谢jonrshape,我现在知道,__getattr__(self, attr)当调用方法时,也会在访问属性时调用方法.但我怎么区分__getattr__,如果attr来自一个方法调用或属性的访问,以及如何让潜在的方法调用的参数?

tom*_*mas 9

这是我想出来的,它的行为就像方法存在一样.

首先,让我们建立了一两件事:你不能区分__getattr__是否attr来自一个函数调用或"属性访问",因为一类方法是一个属性类的.所以有人可以访问该方法,即使他们不打算调用它,如:

class Test:
    def method(self):
        print "Hi, I am method"

>> t = Test()
>> t.method # just access the method "as an attribute"
<bound method Test.method of <__main__.Test instance at 0x10a970c68>>

>> t.method() # actually call the method
Hi, I am method
Run Code Online (Sandbox Code Playgroud)

因此,我能想到的最接近的是这种行为:

创建一个A类,这样:

  1. 当我们尝试访问该类中已存在的属性/方法时,请执行normal并返回所请求的属性/方法.
  2. 当我们尝试访问类定义中不存在的内容时,将其视为类方法,并为所有此类方法提供1个全局处理程序.

我将首先编写类定义,然后展示访问不存在的方法的行为与访问存在的方法完全相同,无论您是访问它还是实际调用它.

班级定义:

class A(object):
    def __init__(self):
        self.x = 1 # set some attribute

    def __getattr__(self,attr):
        try:
            return super(A, self).__getattr__(attr)
        except AttributeError:
            return self.__get_global_handler(attr)

    def __get_global_handler(self, name):
        # Do anything that you need to do before simulating the method call
        handler = self.__global_handler
        handler.im_func.func_name = name # Change the method's name
        return handler

    def __global_handler(self, *args, **kwargs):
        # Do something with these arguments
        print "I am an imaginary method with name %s" % self.__global_handler.im_func.func_name
        print "My arguments are: " + str(args)
        print "My keyword arguments are: " + str(kwargs)

    def real_method(self, *args, **kwargs):
        print "I am a method that you actually defined"
        print "My name is %s" % self.real_method.im_func.func_name
        print "My arguments are: " + str(args)
        print "My keyword arguments are: " + str(kwargs)
Run Code Online (Sandbox Code Playgroud)

我添加了这个方法real_method,所以我在类中实际存在一些东西来比较它的行为和'虚构方法'的行为

这是结果:

>> a = A() 
>> # First let's try simple access (no method call)
>> a.real_method # The method that is actually defined in the class
<bound method A.real_method of <test.A object at 0x10a9784d0>>

>> a.imaginary_method # Some method that is not defined
<bound method A.imaginary_method of <test.A object at 0x10a9784d0>>

>> # Now let's try to call each of these methods
>> a.real_method(1, 2, x=3, y=4)
I am a method that you actually defined
My name is real_method
My arguments are: (1, 2)
My keyword arguments are: {'y': 4, 'x': 3}

>> a.imaginary_method(1, 2, x=3, y=4)
I am an imaginary method with name imaginary_method
My arguments are: (1, 2)
My keyword arguments are: {'y': 4, 'x': 3}

>> # Now let's try to access the x attribute, just to make sure that 'regular' attribute access works fine as well
>> a.x
1
Run Code Online (Sandbox Code Playgroud)


Ada*_*ith 5

unittest.mock.Mock 默认情况下执行此操作。

from unittest.mock import Mock

a = Mock()

a.arbitrary_method()                             # No error
a.arbitrary_method.called                        # True
a.new_method
a.new_method.called                              # False
a.new_method("some", "args")
a.new_method.called                              # True
a.new_method.assert_called_with("some", "args")  # No error
a.new_method_assert_called_with("other", "args") # AssertionError
Run Code Online (Sandbox Code Playgroud)