如何检查Python类是否具有特定方法?

2 投票
3 回答
7135 浏览
提问于 2025-04-18 17:12
class C(Test):
    def __init__(self):
        print "in C init"
        super(C, self).__init__()

    def setup(self):
        print "\tin C setup"

    def runtest(self):
        print "\t\tin C runtest"

    def teardown(self):
        print "\t\t\tin C teardown"

我在不同的模块里有一些类,比如类 ABC 等等。在一个模块中,我只考虑那些有设置(setup)和拆卸(teardown)方法的类。假设类 A 没有设置方法,我就不想在我的程序后续部分考虑它,因为我正在建立一个包含有设置和运行测试(runtest)模块的类的列表。有没有什么 Python 函数可以用来解决这个问题?处理这个问题的正确方法是什么?

3 个回答

2

你可以使用 getattrcallable 这两个方法。

setup_method = getattr(your_object, "setup_method", None)
if callable(setup_method):
    setup_method(self.path.parent_op)

首先,检查这个对象是否有一个叫做 "setup_method" 的属性,然后再检查这个属性是不是一个方法,最后再调用它。

4

你可以在类本身上使用 hasattrcallable,因为类本身也是对象。也就是说,你可以这样做:

if hasattr( C, 'setup' ) and callable( C.setup ):
      classes_with_setup.append(C)

或者,用列表推导的方式来写:

classes_with_setup=[ U for U in [A,B,C...] if hasattr(U,'setup') and callable(U.setup)]

这样就可以设置一个包含这些特性的类的列表。

这种方法可以检测到继承关系:

In [1]: class A(object):
   ...:     def f(self):
   ...:         print 'hi'
   ...:         

In [2]: class B(A):
   ...:     pass
   ...: 

In [3]: hasattr(A,'f')
Out[3]: True

In [4]: hasattr(B,'f')
Out[4]: True

In [5]: hasattr(B,'f') and callable(B.f)
Out[5]: True
5

我认为这是一个使用抽象基类的好例子。

class Test(metaclass=ABCMeta):
    @abstractmethod
    def setup(self):
        ...

    @abstractmethod
    def teardown(self):
        ...

    @classmethod
    def __subclasshook__(cls, C):
        if cls is Test:
            if (any("setup" in B.__dict__ for B in C.__mro__) and 
               any("teardown" in B.__dict__ for B in C.__mro___)):
                return True
        return NotImplemented

这里定义了一个类型叫做Test,还有一个__subclasshook__函数,这个函数用来检查一个类是否定义了setup()teardown()这两个方法。这意味着任何符合条件的类都会被当作Test的子类来看待——也就是说,调用issubclass(C, Test)时会返回True

当然,你也可以手动检查,使用和__subclasshook__函数相同的方法,但抽象基类提供了一种很好的(而且是标准的)方式来定义你想要的契约。

撰写回答