类对象是单例的吗?

2024-09-27 07:27:22 发布

您现在位置:Python中文网/ 问答频道 /正文

如果我们有x = type(a)和{},这是否一定意味着{}?在

这是一个反例,但这是个骗局:

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

我无法创造这样的反例:

^{2}$

为了澄清我的问题-没有重写equality运算符来做一些疯狂的事情,一个类是否可能存在于两个不同的内存位置,或者导入系统是否以某种方式阻止了这种情况?在

如果是这样,我们如何证明这种行为-例如,用reload或{}做奇怪的事情?在

如果没有,这是由语言保证的还是有文档记录的?在


结语

# 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)

因此,虽然使用^{}的代码可以通过类标识来中断类型检查,但无论如何它也会中断isinstance。在


Tags: fromimportfalsetrueistypesyspass
2条回答

不,不可能创建两个比较相等而不完全相同的类对象,除非通过搞乱元类__eq__方法。在

不过,这种行为并不是类独有的。这是没有在类中定义__eq__方法的任何对象的默认行为。行为继承自object,它是所有其他(新样式)类的基类。它只对具有其他语义的内置类型(例如比较其内容的容器类型)和定义自己的__eq__运算符的自定义类重写。在

至于在不同的内存位置获取对同一类的两个不同引用,由于Python的对象语义,这是不可能的。对象的内存位置是其标识(至少在cpython中)。另一个具有相同内容的类可以存在于其他地方,但是就像您的A1A2示例中一样,所有Python逻辑都将它视为一个不同的对象。在

我不知道任何关于==如何作用于类型的文档,但是它肯定是通过标识来工作的。您可以看到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继承默认的相等比较,这是一个指针比较:

^{pr2}$

相关问题 更多 >

    热门问题