0

私は定期的に、Pythonで許可されているダイナミシティの一部を少し悪用しようとしていることに気付きます(ここではpython3を使用していますが、多くの違いはないはずです)。

unittest.TestCaseこの場合、実行時に作成されたいくつかのメソッドに、私の1つの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)

(あるいは、私は多くの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:バインドされていないメソッドをバインドしますか?)を見つけましたが、それらのいずれも、その内部でターゲットクラスの他のバインドされたメソッドを呼び出すメソッドのバインドを扱っていません

メタクラス(http://docs.python.org/py3k/reference/datamodel.html#customizing-class-creation)も調べようとしましたが、私がやろうとしていることと一致していないようです。

4

2 に答える 2

1

メソッドをクラスに直接追加する場合は、自分でメソッドをバインドする必要はありません。

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

def getfoo(self):
  return self.foo

C.getfoo = getfoo
c=C()
print(c.getfoo())
于 2012-04-19T17:39:24.590 に答える
1

Python 2には、関数、バインドされていないメソッド、バインドされたメソッドがあります。メソッドをインスタンスとしてクラスにバインドしても、バインドされていないメソッドにはなりません。つまり、クラスメソッドまたはメタクラスメソッドと同等になります。

Python 3には、バインドされたメソッドとバインドされていないメソッドはなく、関数とメソッドだけがあります。したがって、assertEqualを関数として取得している場合は、testxメソッドがインスタンスにバインドされていないことを意味します。これが実際の問題です。

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では、他の回答が示唆するように、関数をクラスに割り当てるだけで機能しますが、あなたの場合の本当の問題は、部分的なオブジェクトがメソッドにならないことです。

あなたのケースの簡単な解決策は、部分的な代わりにラムダを使用することです。

それ以外の:

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)
于 2012-04-19T18:02:23.030 に答える