最简单的方法在类上 禁止绑定一个函数?

2024-09-30 20:28:43 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在编写一些支持代码,以加快通过RequestFactory调用Django视图(在别处声明的函数)。我将大部分测试属性直接存储在类上,而不是它们的实例上。在

我要做的一件事是在类中存储我感兴趣的函数,以便以后调用它(使用inspect向它提供正确的参数)。在

以下是我的总体意图:

def to_test(var1, var2, var3):
    "this function has nothing to do with MyTest"
    assert isinstance(var1, basestring), "not an instance"

class MyTest(unittest.TestCase):

    #only using this attribute to store the function to 
    #test, not to bind that function
    func_under_test = to_test

    def test_with_abc(self):
        self.func_under_test("a","b", "c")

    def test_with_def(self):
        self.func_under_test("d","e", "f")

但是一旦我把一个函数赋给一个类,它就被绑定到了这个类上。在

99%的时候都很好。只是不在这里,因为它在调用时获取了错误的参数。相反,在每个类上,我都重新声明某个,这样我就可以将函数赋给它,而不是直接在类上。甚至元类也没有帮助。在

一些示例代码

我想要的是FunctionStore1/2的语法。实际上,我最接近的是FunctionStore3/4/6,但它们要求您记住每次复制和粘贴小的_声明。没什么大不了的,只是粗俗。在

^{pr2}$

输出:

no `_` on FunctionStore5:e:name '_' is not defined

no `_` dict on FunctionStore7:e:name '_' is not defined

 calling FunctionStore1
    FunctionStore1: exception:unbound method regular_function() must be called with FunctionStore1 instance as first argument (got str instance instead)

 calling FunctionStore2
    FunctionStore2: exception:unbound method regular_function2() must be called with FunctionStore2 instance as first argument (got str instance instead)

 calling FunctionStore3Works
    regular_function({'args': ('FunctionStore3Works',), 'kwds': {}})

 calling FunctionStore4Works
    regular_function2({'args': ('FunctionStore4Works',), 'kwds': {}})

 calling FunctionStore5
    FunctionStore5: no func_to_check

 calling FunctionStore6Works
    regular_function({'args': ('FunctionStore6Works',), 'kwds': {}})

 calling FunctionStore7Meta
    FunctionStore7Meta: no func_to_check
        even if FunctionStore7Meta does have a `_`, now:{}

Tags: toinstance函数notestself声明def
2条回答

属于一个类的函数有三种不同的方式:

def _instance_method(self, *args):
    print('self:', self)
    print('instance_method args:', args, '\n')

def _class_method(cls, *args):
    print('cls:', cls)
    print('class_method args:', args, '\n')

def _static_method(*args):
    print('static_method args:', args, '\n')

class TestClass:
    instance_method = _instance_method
    class_method = classmethod(_class_method)
    static_method = staticmethod(_static_method)

实例方法隐式传递对实例的引用。类方法隐式传递对类的引用。实例或类都未传递静态方法。以下用法作为示例:

^{pr2}$

请注意,当函数在类的主体中定义时,通常使用修饰符来实现相同的结构。在

class TestClass:
    def instance_method(self, *args): pass

    @classmethod
    def class_method(cls, *args): pass

    @staticmethod
    def static_method(*args): pass

注意,这只是一种控制隐式传递给函数的参数的机制。这与您的情况有关,因为您有一个独立于类定义定义的函数,因此将实例或类传递给函数是没有意义的。在

还应该注意的是,在类定义完成之后,可以直接将函数分配给类。在

class FunctionStore1: pass
FunctionStore1.func_to_check = func_to_check

我个人认为这可能是你的案子最好的模式。它清楚地表明您正在将有问题的函数作为成员数据附加到类。此模式还允许使用舒适的“没有staticmethod的用例”透视图。在

这也可以通过使用装饰器来完成。在

def bind_function(func):
    def wrapper(cls):
        setattr(cls, func.__name__, func)
        return cls
    return wrapper

def func_to_check(*args):
    print('args:', args, '\n')

@bind_function(func_to_check)
class TestClass: pass

TestClass.func_to_check('args')
# args: ('args',) 

这是一个很好的模式,因为您可以在类定义之前声明要绑定的函数,而不是在它之后很容易错过的地方。它还提供了很多灵活性,如果你想改变事情。例如,您可以使用一个静态名称,而不是动态地使用func.__name__作为class属性。或者,您可以允许将多个函数传递给decorator(甚至可以委托确定参数)。在

您可以将函数包装在staticmethod中:

class FunctionStore1(object):
    "this fails, expecting an instance"
    func_to_check = staticmethod(regular_function)

相关问题 更多 >