如何在Python中比较两个类/类型?
我在一个叫做 classes.py
的模块里定义了两个类:
class ClassA(object):
pass
class ClassB(object):
pass
然后在另一个模块里,我正在获取这个模块的属性:
import classes
Class1 = getattr(classes, 'ClassA')
Class2 = getattr(classes, 'ClassA')
print type(Class1) == type(Class2)
Class3 = getattr(classes, 'ClassA')
Class4 = getattr(classes, 'ClassB')
print type(Class3) == type(Class4)
我发现这两种类型的比较都返回了 True,这不是我预期的结果。
我该如何使用 Python 自带的类型值来比较类的类型呢?
4 个回答
除了其他回答之外:
Python中有一个叫做元类的概念,简单来说就是“类的类”。这意味着,在Python中,类本身也是一个对象,而且它有自己的类,可以通过内置的 type
函数来访问。
因为 ClassA
和 ClassB
默认都是同一个元类的实例,所以它们的比较结果是True。
如果你想了解更多关于元类的内容,可以看看这个StackOverflow的帖子,是个不错的开始。
你在比较类对象的类型,这些对象的类型都是 'type'
。
如果你只是想比较类本身,那就直接比较它们:
print Class3 == Class4
如果你想检查两个类型是否相等,那么你应该使用 is
操作符。
举个例子:我们可以创建一个简单的元类
class StupidMetaClass(type):
def __eq__(self, other):
return False
然后基于这个元类创建一个类:
在 Python 2 中
class StupidClass(object): __metaclass__ = StupidMetaClass
在 Python 3 中
class StupidClass(metaclass=StupidMetaClass): pass
接下来做一个简单的检查
>>> StupidClass == StupidClass
结果是 False
,而
>>> StupidClass is StupidClass
则返回预期的 True
值。
所以我们可以看到,==
操作符在类上是可以被重载的,但没有简单的方法可以改变 is
操作符的行为。
解释
这就是为什么你的比较没有按预期工作的原因
>>> class ClassA(object):
... pass
...
>>> class ClassB(object):
... pass
...
>>> type(ClassB)
<class 'type'>
>>> type(ClassA)
<class 'type'>
>>> type(ClassA) == type(ClassB)
True
但是为什么 ClassA
和 ClassB
会有相同的类型 type
呢?引用一下文档:
默认情况下,类是通过
type()
创建的。类的主体在一个新的命名空间中执行,类名被局部绑定到type(name, bases, namespace)
的结果上。
举个例子:
>>> ClassB
<class '__main__.ClassB'>
>>> type('ClassB', (), {})
<class '__main__.ClassB'>
>>> type(ClassB)
<class 'type'>
>>> type(type('ClassB', (), {}))
<class 'type'>
获取 ClassB
的类型和获取 type('ClassB', (), {})
的类型是完全一样的,结果都是 type
。
解决方案
直接比较它们(不使用 type()
函数):
>>> ClassA
<class '__main__.ClassA'>
>>> ClassB
<class '__main__.ClassB'>
>>> ClassA == ClassB
False
或者初始化它们,然后比较它们对象的类型:
>>> a = ClassA()
>>> b = ClassB()
>>> type(a)
<class '__main__.ClassA'>
>>> type(b)
<class '__main__.ClassB'>
>>> type(a) == type(b)
False
顺便说一下,你也可以在类的比较中用 is
替代 ==
。