Python 如何使用自己的方法从外部库扩充类?

Python 如何使用自己的方法从外部库扩充类?,python,class,inheritance,methods,monkeypatching,Python,Class,Inheritance,Methods,Monkeypatching,我需要在django测试一些特殊情况。我试图通过编写自己的测试用例来扩展现有的django测试。以下是我目前的做法 from django.tests import TestCase # define my own method as a function def assertOptionsEqual(self, first, second): # logic here pass # Attach the method to the TestCase class. This

我需要在django测试一些特殊情况。我试图通过编写自己的测试用例来扩展现有的django测试。以下是我目前的做法

from django.tests import TestCase

# define my own method as a function
def assertOptionsEqual(self, first, second):
    # logic here
    pass

# Attach the method to the TestCase class. This feels inelegant!
TestCase.assertOptionsEqual = assertOptionsEqual

# tests go here
class KnownGoodInputs(TestCase):
    def test_good_options(self):
        self.assertOptionsEqual(...)
虽然这样做有效,但将方法定义为以
self
作为第一个参数的函数,然后将其附加到
TestCase
会让人觉得不雅观。有没有更好的方法用我自己的方法扩充
TestCase
类?我可以做到这一点

class MyTestCase(TestCase):
    def assertOptionsEqual(self, first, second):
        ...

并对所有测试使用
MyTestCase
,但不知道是否有更好的替代方案。谢谢

我想你已经涵盖了这两个选项。您可以使用子类或monkeypatch。通常,monkeypatching,即在运行时实际更改第三方类是不受欢迎的,但根据您需要进行的更改,这可能是解决bug或确保每次使用该类时都有新方法的唯一方法

因为使用您的方法的唯一测试将是您的测试,所以monkeypatching是不必要的,并且子类化
TestCase
是非常合理的。通常,当需要扩充现有类的方法时,您会使用monkeypatching。例如,如果您希望在现有测试用例中对
TestCase.assertEqual
的调用增加逻辑以与
Option
对象进行比较,您可以通过执行以下操作来monkeypatch
TestCase.assertEqual
以包括自定义逻辑及其正常逻辑:

originalAssertEqual = TestCase.assertEqual
def newAssertEqual(self, first, second):
    result = originalAssertEqual(first, second)
    if isinstance(first, Option) and isinstance(second, Option):
        # do your custom comparison
    return result
TestCase.assertEqual = newAssertEqual 
然而,至少在这个例子中,似乎子类和monkeypatches都是不必要的

假设问题是调用
self.assertEqual(firstOptions,secondOptions)
失败,即使
选项
实例相等,也不需要编写新的
assertOptionsEqual
方法。您可能只需要使用
选项
对象来正确定义
\uuuuueq\uuuu

假设你有:

class KnownGoodInputs(TestCase):
    def test_good_options(self):
        first, second = systemUnderTestGetOptions(...)
        self.assertOptionsEqual(first, second)
上面的
first
second
的类别是什么

对于所有Python内置类型,
assertEqual
应该可以工作。对于自定义
选项
类,只需执行以下操作:

类选项(对象): def初始化(自身): 使用_foo=False 使用_bar=True

def __eq__(self, other):
    if (self.use_foo == other.use_foo and
        self.use_bar == other.use_bar):
        return True
    return False
然后假设
first
second
Option
的实例,您可以编写测试,如下所示:

class KnownGoodInputs(TestCase):
    def test_good_options(self):
        first, second = systemUnderTestGetOptions(...)
        self.assertEqual(first, second)

那就直接子类化并使用另一个方法名怎么样?谢谢你的详细回答!尝试定义
\uuuu eq\uuuu
是第一选择。但是,被比较的对象是Django原生对象(聚合、查询集等),它们没有定义
\uuuuueq\uuuuuu
。因此,我要么必须为一些本地Django对象monkeypatch一个
\uuuuuueq\uuuuuu
方法,要么monkeypatch测试用例。所以我想我是想从这两种罪恶中选择较小的一种!;)