我经常发现自己试图略微滥用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),但它似乎与我尝试做的事情不相符
答案 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)