绑定一个调用类中其他方法的方法

时间:2012-04-19 17:32:46

标签: python dynamic methods bind

我经常发现自己试图略微滥用python允许的一些恐龙(我在这里使用python3,但不应该有很多不同之处)。

在这种情况下,我想在我的unittest.TestCase中将一个test_方法拆分为在运行时创建的几个方法。

(这是关于罗马数字的卡塔,但我实际上并没有TDD:我后来写了测试)

这是测试:

class TestNumbers(TestCase):
    def test_number(self):
            for i in range(3000):
                    self.assertEqual(i, roman_to_int(int_to_roman(i)))

这就是我试图写它的方式:

from functools import partial
from types import MethodType

class TestNumbers(TestCase):
    pass

def test_number(self, n):
    self.assertEqual(n, roman_to_int(int_to_roman(n)))

for i in range(3000):
    name = str(i)
    test_method = MethodType(partial(test_number, n=i), TestNumbers)
    setattr(TestNumbers, "test" + name, test_method)

(或者,我也尝试用dinamically创建大量的TestCase子类和setattr(globals(), ...)它们)

我知道:这并没有太多的目的,它也可能更慢,等等。但这只是一个POC,我试图了解如何让它工作

通过使用MethodType,测试成为一个绑定方法,但在内部,assertEqual显然成为一个函数,当试图调用它时,它会失败TypeError: assertEqual() takes at least 3 arguments (2 given)

我尝试将test_number更改为

def test_number(self, n):
    self.assertEqual(self, n, roman_to_int(int_to_roman(n)))

但这只会在隐藏的TestCase方法中更深入地发现同样的问题:TypeError: _getAssertEqualityFunc() takes exactly 3 arguments (2 given)

我在这里查看了stackoverflow并找到了类似的问题(比如Python: Bind an Unbound Method?),但是没有一个涉及绑定一个方法,在其中调用目标类的其他绑定方法

我也尝试研究元类(http://docs.python.org/py3k/reference/datamodel.html#customizing-class-creation),但它似乎与我尝试做的事情不相符

2 个答案:

答案 0 :(得分:1)

如果您将该方法直接添加到该类中,则无需自己绑定它。

class C(object):
  def __init__(self):
    self.foo = 42

def getfoo(self):
  return self.foo

C.getfoo = getfoo
c=C()
print(c.getfoo())

答案 1 :(得分:1)

在Python 2上有函数,未绑定和绑定方法。将方法绑定到类作为实例不会使其成为未绑定的方法,使其等同于类方法或元类方法。

在Python 3上,不再有绑定和未绑定的方法,只有函数和方法,所以如果你将assertEqual作为一个函数,那就意味着你的testx方法没有被绑定到实例,这才是真正的问题。 / p>

在Python 2上,你所要做的就是在MethodType调用上为实例分配None,它会起作用。

所以,替换:

test_method = MethodType(partial(test_number, n=i), TestNumbers)

有关:

test_method = MethodType(partial(test_number, n=i), None, TestNumbers)

在Python 3上,只需将函数分配给类就可以了,就像其他答案所示,但在你的情况下,真正的问题是部分对象不会成为方法。

您的案例的简单解决方案是使用lambda而不是partial。

而不是:

test_method = MethodType(partial(test_number, n=i), TestNumbers)

使用:

test_method = lambda self: test_number(self, i)

它应该有用......

真正的解决方案是重写部分,以便返回具有所需参数的实际函数。您可以使用旧版本和额外默认参数中的所有内容创建函数实例。像这样:

code = test_number.__code__
globals = test_number.__globals__
closure = test_number.__closure__

testx = FunctionType(code, globals, "test"+name, (i,), closure)
setattr(TestNumbers, "test" + name, testx)