如何(在运行时)检查一个类是否是另一个类的子类?

问题:如何(在运行时)检查一个类是否是另一个类的子类?

假设我有一个西服类和西服的四个子类:Heart,Spade,Diamond,Club。

class Suit:
   ...
class Heart(Suit):
   ...
class Spade(Suit):
   ...
class Diamond(Suit):
   ...
class Club(Suit):
   ...

我有一个方法,该方法接收西装作为参数,这是一个类对象,而不是实例。更准确地说,它可能仅接收以下四个值之一:Heart,Spade,Diamond,Club。我该如何做出保证这种事情的断言?就像是:

def my_method(suit):
   assert(suit subclass of Suit)
   ...

我正在使用Python 3。

Let’s say that I have a class Suit and four subclasses of suit: Heart, Spade, Diamond, Club.

class Suit:
   ...
class Heart(Suit):
   ...
class Spade(Suit):
   ...
class Diamond(Suit):
   ...
class Club(Suit):
   ...

I have a method which receives a suit as a parameter, which is a class object, not an instance. More precisely, it may receive only one of the four values: Heart, Spade, Diamond, Club. How can I make an assertion which ensures such a thing? Something like:

def my_method(suit):
   assert(suit subclass of Suit)
   ...

I’m using Python 3.


回答 0

您可以使用issubclass()像这样assert issubclass(suit, Suit)

You can use issubclass() like this assert issubclass(suit, Suit).


回答 1

issubclass(class, classinfo)

摘抄:

如果class是的子类(直接,间接或虚拟), 则返回true classinfo

issubclass(class, classinfo)

Excerpt:

Return true if class is a subclass (direct, indirect or virtual) of classinfo.


回答 2

isinstance如果您有实例或issubclass类,则可以使用。通常认为这是一个坏主意。通常,在Python中,您可以通过尝试对某个对象进行处理来确定该对象是否具有某种处理能力。

You can use isinstance if you have an instance, or issubclass if you have a class. Normally thought its a bad idea. Normally in Python you work out if an object is capable of something by attempting to do that thing to it.


回答 3

issubclass(sub, sup)如果给定的子类布尔函数返回真sub不愧是超类的子类sup

The issubclass(sub, sup) boolean function returns true if the given subclass sub is indeed a subclass of the superclass sup.


回答 4

issubclass 最小的可运行示例

这是带有一些断言的更完整的示例:

#!/usr/bin/env python3

class Base:
    pass

class Derived(Base):
    pass

base = Base()
derived = Derived()

# Basic usage.
assert issubclass(Derived, Base)
assert not issubclass(Base, Derived)

# True for same object.
assert issubclass(Base, Base)

# Cannot use object of class.
try:
    issubclass(derived, Base)
except TypeError:
    pass
else:
    assert False

# Do this instead.
assert isinstance(derived, Base)

GitHub上游

已在Python 3.5.2中测试。

issubclass minimal runnable example

Here is a more complete example with some assertions:

#!/usr/bin/env python3

class Base:
    pass

class Derived(Base):
    pass

base = Base()
derived = Derived()

# Basic usage.
assert issubclass(Derived, Base)
assert not issubclass(Base, Derived)

# True for same object.
assert issubclass(Base, Base)

# Cannot use object of class.
try:
    issubclass(derived, Base)
except TypeError:
    pass
else:
    assert False

# Do this instead.
assert isinstance(derived, Base)

GitHub upstream.

Tested in Python 3.5.2.


回答 5

您可以使用内置的issubclass。但是通常认为类型检查是不必要的,因为您可以使用鸭子类型。

You can use the builtin issubclass. But type checking is usually seen as unneccessary because you can use duck-typing.


回答 6

使用issubclass似乎是编写日志级别的一种干净方法。使用它有点奇怪…但是它看起来比其他选项更干净。

class Error(object): pass
class Warn(Error): pass
class Info(Warn): pass
class Debug(Info): pass

class Logger():
    LEVEL = Info

    @staticmethod
    def log(text,level):
        if issubclass(Logger.LEVEL,level):
            print(text)
    @staticmethod
    def debug(text):
        Logger.log(text,Debug)   
    @staticmethod
    def info(text):
        Logger.log(text,Info)
    @staticmethod
    def warn(text):
        Logger.log(text,Warn)
    @staticmethod
    def error(text):
        Logger.log(text,Error)

Using issubclass seemed like a clean way to write loglevels. It kinda feels odd using it… but it seems cleaner than other options.

class Error(object): pass
class Warn(Error): pass
class Info(Warn): pass
class Debug(Info): pass

class Logger():
    LEVEL = Info

    @staticmethod
    def log(text,level):
        if issubclass(Logger.LEVEL,level):
            print(text)
    @staticmethod
    def debug(text):
        Logger.log(text,Debug)   
    @staticmethod
    def info(text):
        Logger.log(text,Info)
    @staticmethod
    def warn(text):
        Logger.log(text,Warn)
    @staticmethod
    def error(text):
        Logger.log(text,Error)

回答 7

根据Python文档,我们还可以使用class.__mro__属性或class.mro()方法:

class Suit:
    pass
class Heart(Suit):
    pass
class Spade(Suit):
    pass
class Diamond(Suit):
    pass
class Club(Suit):
    pass

>>> Heart.mro()
[<class '__main__.Heart'>, <class '__main__.Suit'>, <class 'object'>]
>>> Heart.__mro__
(<class '__main__.Heart'>, <class '__main__.Suit'>, <class 'object'>)

Suit in Heart.mro()  # True
object in Heart.__mro__  # True
Spade in Heart.mro()  # False

According to the Python doc, we can also use class.__mro__ attribute or class.mro() method:

class Suit:
    pass
class Heart(Suit):
    pass
class Spade(Suit):
    pass
class Diamond(Suit):
    pass
class Club(Suit):
    pass

>>> Heart.mro()
[<class '__main__.Heart'>, <class '__main__.Suit'>, <class 'object'>]
>>> Heart.__mro__
(<class '__main__.Heart'>, <class '__main__.Suit'>, <class 'object'>)

Suit in Heart.mro()  # True
object in Heart.__mro__  # True
Spade in Heart.mro()  # False

回答 8

#issubclass(child,parent)

class a:
    pass
class b(a):
    pass
class c(b):
    pass

print(issubclass(c,b))#it returns true
#issubclass(child,parent)

class a:
    pass
class b(a):
    pass
class c(b):
    pass

print(issubclass(c,b))#it returns true