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


195

假设我有一个西服类和西服的四个子类: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。


1
@Leopd:真的不清楚吗?我已经确切说明了可以my_method作为参数获得的四个值到底是什么:“它可能只接收四个值之一:Heart,Spade,Diamond,Club”。这些值是类对象,而不是类实例。对我来说似乎很清楚,尽管我认为您对模糊性是正确的,因为答案确实涵盖了这两种可能性。如果您的字眼更清晰,欢迎您编辑问题。感谢您的评论。
悄悄的

@snakile是的,目前尚不清楚。由于依赖于任何人的自我表达的正确性,在这个话题上是薄冰。许多新来者无法理解一切都是Python中的对象,可能会表达一件事,但又想到了另一件事。这是现实,并且除了纯粹性之外,期待新手的这种行为是很合理的。留下声誉是唯一直接的暗示,无论您在这里的表达是正确的,还是我应该说“正确性”。我理解希望考虑到您的知识的愿望,但不考虑不断更新的新来者仍然是不合理的。
n611x007 2014年

1
@snakile以及使用合理的命名约定为此类参数名称加后缀_class,使它们像like 可能是合理的suit_class。我在一个相关的问题中提出了这样的命名约定。
n611x007 2014年

建议在示例代码中添加四行my_method(Heart) my_method(Spade)...
Bob Stein

对于不能保证要测试的变量是类的情况,您可以在Python 3 上添加条件inspect.isclass或直接isinstance(myvar, type)在Python 3中使用,因为issubclass如果传递非类会引发错误。看到这个答案。我会在下面的答案中发表评论,但它从来没有见过。
totalhack

Answers:


223

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


55
“但是你为什么要做这样的事情?” -因为您需要确保一个容器类是同质的,并且唯一的方法是在插入时检查类型?
亚当·帕金

139
如果在Stack Overflow上有一件不变的事情,那就是任何带有暗示isinstance或issubclass的答案的问题也将伴随着鸭子类型的讲座!
本·罗伯茨

26
我遇到了这个问题,试图找出如何为图像处理应用程序检测我的numpy dtype是float还是int。如果是浮点型,则约定是在0.0到1.0之间进行归一化;如果是int,则约定是0到255。我可以尝试各种方式来尝试使图像变庸俗,但更直接只需问“你是鸭子”,然后相应地调整我的操作范围即可。
Omegaman

28
子类测试使许多事情(尤其是Django模型)的单元测试变得容易得多。“ Python不是Java。” 为什么python程序员必须在肩膀上放这样的芯片?
迈克尔·培根

20
不赞成,纯粹是因为最后的言论缺乏想象力和自大。对为什么可能不需要这样做的解释会更友好,更有用。
Michael Scheper


26

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


如果发现无法使用该功能怎么办?您是否发现异常并尝试其他方法?
错误的用户名,2016年

2
@wrongusername:是的,是“ Pythonic”方式。我认为此风俗是有好处的,因此只要它能使我的代码清晰明了,我就遵循它。有一个关于一个很好的讨论在这里:stackoverflow.com/questions/7604636/...
迈克尔Scheper

8
@Michael Scheper:我必须说,如果那是pythonic的方式,那么我真的很讨厌pythonic的方式。IMO,绝对不应将异常用于控制流。如果您认为可能会发生错误,请防止错误……不要将其视为GOTO。不过,您发布了有趣的链接
leviathanbadger

@ aboveyou00:听起来像您正在谈论的那种情况“只要它能使我的代码清晰即可”。但是,我并不是所有Python习俗的忠实拥护者,因为许多人滥用EAFP原则并最终创建了难以发现的错误。
Michael Scheper

定义合同时,此检查非常方便。例如,一个接收对象的构造函数:我们想断言所接收的对象是给定类的实例,通过这样做,我们通知代码读取器构造函数的期望。
mastropi


2

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中测试。


1

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


1

使用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)

0

根据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

-5
#issubclass(child,parent)

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

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

1
SO代码不适合仅使用代码的答案,因此应始终在代码中添加一些说明性文字。但是,此答案是多余的:它不添加先前答案中未提及的信息。
下午16年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.