2012-04-19 107 views
0

我經常發現自己試圖稍微濫用python允許的一些dinamicity(我在這裏使用python3,但不應該有很多差異)。綁定調用類內其他方法的方法

在這種情況下,我想將我的unittest.TestCase中的單個test_方法拆分爲在運行時創建的幾個方法。

(這是一個關於羅馬數字卡塔,但我居然沒有TDD:我寫的測試版本)

這是測試:

​​

這就是我試着寫它:

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)

我看着這裏stacko verflow和發現類似的問題(如Python: Bind an Unbound Method?),但沒有一個處理綁定內部的方法,它調用目標類的其他綁定方法

我也試圖查看元類(http://docs.python.org/py3k/reference/datamodel.html#customizing-class-creation),但它不似乎與我正在嘗試做的事情相匹配

回答

1

在Python 2上有函數,未綁定和綁定方法。將一個方法作爲一個實例綁定到一個類上並不會使它成爲一個未綁定的方法,它使它成爲一個類方法或一個元類方法的等價物。

在Python 3中,不再有綁定和未綁定的方法,只是函數和方法,所以如果您將assertEqual作爲函數獲取,這意味着您的testx方法未綁定到實例,這是真正的問題。

在Python 2上,你所要做的就是將None分配給MethodType調用中的實例,它將起作用。

所以,替換:

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

爲:

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

在Python 3中只分配你的情況函數的類會的工作,像其他答案建議,但真正的問題部分對象不成爲方法。

您的案例的一個簡單的解決方案是使用lambda而不是部分。

相反的:

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) 
+0

assertEqual **不會**成爲一個函數顯然:http://paste.pocoo.org/show/584485/ 和python3 MethodType只有2個參數:http ://paste.pocoo.org/show/584486/ – berdario 2012-04-20 08:30:20

+0

在Python 3上,沒有未綁定和綁定的方法,只是方法。我改變了相應的答案。 – 2012-04-20 14:21:18

+0

_partial對象不會變成方法_我完全沒有想到!感謝:D – berdario 2012-04-20 14:45:44

1

如果您直接將方法添加到類中,則無需自己綁定它。

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

def getfoo(self): 
    return self.foo 

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

MHN,是的......即使我從一個子類調用它和dinamically設置它的名字,它的工作原理http://paste.pocoo.org/show/584190/但是當試圖在unittest.TestCase上做它會失敗......也許這是由於testrunner實例化類的方式?我會稍後再研究它,並最終更新問題 – berdario 2012-04-19 18:04:45