如果我们有x = type(a)
和x == y
,那是否一定意味着x is y
?
这是一个反例,但它是一个骗子:
>>> class BrokenEq(type):
... def __eq__(cls, other):
... return True
...
>>> class A(metaclass=BrokenEq):
... pass
...
>>> a = A()
>>> x = type(a)
>>> x == A, x is A
(True, True)
>>> x == BrokenEq, x is BrokenEq
(True, False)
我无法创建这样的反例:
>>> A1 = type('A', (), {})
>>> A2 = type('A', (), {})
>>> a = A1()
>>> x = type(a)
>>> x == A1, x is A1
(True, True)
>>> x == A2, x is A2
(False, False)
为了澄清我的问题 - 而没有覆盖相等的运算符来做一些疯狂的事情,一个类是否可能存在于两个不同的内存位置,或者导入系统是否以某种方式阻止了这个?
如果是这样,我们如何证明这种行为 - 例如,使用reload或__import__
做一些奇怪的事情?
如果没有,是由语言保证还是在任何地方记录?
后记:
# thing.py
class A:
pass
最后,这是澄清我的真实行为(并且它支持Blckknght答案中的声明)
>>> import sys
>>> from thing import A
>>> a = A()
>>> isinstance(a, A), type(a) == A, type(a) is A
(True, True, True)
>>> del sys.modules['thing']
>>> from thing import A
>>> isinstance(a, A), type(a) == A, type(a) is A
(False, False, False)
因此,尽管使用importlib.reload
的代码可能会破坏类标识的类型检查,但无论如何它也会中断isinstance
。
答案 0 :(得分:5)
不,除了通过使用元类__eq__
方法搞乱之外,没有办法创建两个比较相等而不相同的类对象。
这种行为虽然不是类所特有的。它是没有在其类中定义__eq__
方法的任何对象的默认行为。该行为继承自object
,它是所有其他(新式)类的基类。它只覆盖了内置类型,它们具有一些其他相等的语义(例如,比较其内容的容器类型)和定义自己的__eq__
运算符的自定义类。
至于在不同的内存位置对同一个类进行两次不同的引用,由于Python的对象语义,这实际上是不可能的。对象的内存位置其标识(至少在cpython中)。另一个具有相同内容的类可以存在于其他地方,但是在A1
和A2
示例中,它将被所有Python逻辑视为不同的对象。
答案 1 :(得分:5)
我不知道有关==
如何适用于类型的任何文档,但它绝对适用于身份。您可以看到CPython 2.7 implementation是指针比较:
static PyObject*
type_richcompare(PyObject *v, PyObject *w, int op)
{
...
/* Compare addresses */
vv = (Py_uintptr_t)v;
ww = (Py_uintptr_t)w;
switch (op) {
...
case Py_EQ: c = vv == ww; break;
在CPython 3.5中,type
没有实现自己的tp_richcompare
,因此它继承了object
的默认相等比较,这是一个指针比较:
PyTypeObject PyType_Type = {
...
0, /* tp_richcompare */