12

我最近在某处读到,Nonepython 中的特殊值是它自己类的单例对象,特别是NoneType. 这解释了很多,因为涉及Nonepython 的大多数错误都会产生AttributeErrors 而不是一些特殊的“NoneError”或其他东西。

由于所有这些都AttributeErrors反映了所NoneType缺乏的属性,因此我对NoneType 确实具有的属性(如果有的话)产生了兴趣。

我决定对此进行调查NoneType并了解更多信息。我一直发现了解新语言功能的最佳方法是使用它,因此我尝试NoneType在 IDLE 中进行实例化:

>>> n = NoneType()

这产生了一个错误:

Traceback (most recent call last):
File "<pyshell#0>", line 1, in <module>
    n = NoneType()
NameError: name 'NoneType' is not defined

很困惑,我检查None了我是否得到了正确的类型名称。果然,

>>> type(None)
<class 'NoneType'>

现在很困惑,我做了一个快速的谷歌搜索。这表明出于某种原因 NoneType 在 Python 3 中以某种方式被删除。

好吧,我虽然,哈哈!None我可以通过将类型存储在变量中来解决这个问题,因为类是 python 中的对象。这似乎有效:

>>> NoneType = type(None)
>>> n = NoneType()

当我打印 n 时,我得到了几乎我所期望的:

>>> print(n)
None

但后来发生了这样的事情:

>>> n is None
True

和:

>>> id(n)
506768776
>>> id(None)
506768776

我的变量nNone。不仅同类型None。它是None。这不是我所期望的。

我尝试使用dis来获取更多信息NoneType,但是当我打电话时

>>> dis.dis(type(None))

它没有产生任何输出。

然后我尝试调查该__new__方法,几个用户在评论中提到了该方法:

dis.dis(type(None).__new__)
Traceback (most recent call last):
  File "<pyshell#4>", line 1, in <module>
    dis.dis(type(None).__new__)
  File "C:\Python33\lib\dis.py", line 59, in dis
    type(x).__name__)
TypeError: don't know how to disassemble builtin_function_or_method objects
>>> 

更多错误。

以下是我的问题:

  • 为什么n与 Object 完全相同None
  • 为什么将语言设计n为与 Object 完全相同None
  • 甚至如何在 python 中实现这种行为?
4

4 回答 4

7

其他答案描述了如何使用__new__来实现单例,但这并不是 None 的实际实现方式(至少在 cPython 中,我没有研究过其他实现)。

尝试通过创建 None 的实例type(None)()是特殊情况,并最终调用以下 C 函数

static PyObject *
none_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
{
    if (PyTuple_GET_SIZE(args) || (kwargs && PyDict_Size(kwargs))) {
        PyErr_SetString(PyExc_TypeError, "NoneType takes no arguments");
        return NULL;
    }
    Py_RETURN_NONE;
}

并在Py_RETURN_NONE这里定义

/*
_Py_NoneStruct is an object of undefined type which can be used in contexts
where NULL (nil) is not suitable (since NULL often means 'error').

Don't forget to apply Py_INCREF() when returning this value!!!
*/
PyAPI_DATA(PyObject) _Py_NoneStruct; /* Don't use this directly */
#define Py_None (&_Py_NoneStruct)

/* Macro for returning Py_None from a function */
#define Py_RETURN_NONE return Py_INCREF(Py_None), Py_None

将此与创建普通 python 对象的函数进行对比:

PyObject *
_PyObject_New(PyTypeObject *tp)
{
    PyObject *op;
    op = (PyObject *) PyObject_MALLOC(_PyObject_SIZE(tp));
    if (op == NULL)
        return PyErr_NoMemory();
    return PyObject_INIT(op, tp);
}

创建普通对象时,会分配并初始化该对象的内存。当您尝试创建 的新实例时None,您得到的只是对已经存在的_Py_NoneStruct. 这就是为什么,无论你做什么,每个引用都None将是完全相同的对象。

于 2013-12-31T21:45:43.850 回答
5

为什么n与 Object 完全相同None

C 实现保留一个单例实例。 NoneType.__new__正在返回单例实例。

为什么设计语言使得 n 与 是完全相同的 Object None

如果没有单例实例,那么您不能依赖检查x is None,因为is运算符是基于身份的。虽然None == None也是True,但其实有x == None可能不是。有关示例,请参见此答案。TruexNone

甚至如何在 python 中实现这种行为?

您可以通过覆盖来实现此模式__new__。这是一个基本示例:

class Singleton(object):
  _instance = None
  def __new__(cls, *args, **kwargs):
    if Singleton._instance is None:
      Singleton._instance = object.__new__(cls, *args, **kwargs)
    return Singleton._instance

if __name__ == '__main__':
  s1 = Singleton()
  s2 = Singleton()
  print 's1 is s2:', s1 is s2
  print 'id(s1):', id(s1)
  print 'id(s2):', id(s2)

输出:

s1 是 s2:真实
id(s1):4506243152
id(s2):4506243152

当然,这个简单的示例并不意味着无法创建第二个实例。

于 2013-12-31T21:07:15.783 回答
1

为什么 n 与 None 完全相同?

Python 中的许多不可变对象都是实习的,包括None、较小的整数和许多字符串。

演示:

>>> s1='abc'
>>> s2='def'
>>> s3='abc'
>>> id(s1)
4540177408
>>> id(s3)
4540177408    # Note: same as s1
>>> x=1
>>> y=2
>>> z=1
>>> id(x)
4538711696
>>> id(z)
4538711696    # Note: same as x

为什么设计语言使得 n 是与 None 完全相同的对象?

见上文——速度、效率、无歧义性和内存使用等原因是实习不可变对象的原因。

甚至如何在 python 中实现这种行为?

除其他方式外,您可以覆盖__new__以返回相同的对象:

class Singleton(object):
    _instance = None
    def __new__(cls, *args, **kwargs):
        if not cls._instance:
            cls._instance = super(Singleton, cls).__new__(
                                cls, *args, **kwargs)
        return cls._instance

对于字符串,您可以在 Python 2 上调用intern或在 Python 3 上调用sys.intern

于 2013-12-31T21:08:46.827 回答
0
  1. NoneType 覆盖__new__总是返回相同的单例。代码实际上是用 C 编写的,所以dis无济于事,但从概念上讲就是这样。

  2. 只有一个 None 实例更容易处理。无论如何,他们都是平等的。

  3. 通过覆盖__new__...例如

    class MyNoneType(object):
        _common_none = 0
        def __new__(cls):
            return cls._common_none
    
    MyNoneType._common_none = object.__new__(MyNoneType)
    
    m1 = MyNoneType()
    m2 = MyNoneType()
    print(m1 is m2)
    
于 2013-12-31T21:03:26.083 回答