python - NoneType 的实现、原因和细节

标签 python python-3.x singleton nonetype python-internals

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

由于所有这些 AttributeErrors 都反射(reflect)了 NoneType 缺少的属性,我对 NoneType 的属性做了 有,如果有的话。

我决定研究这个 NoneType 并了解更多信息。我一直发现学习新语言特性的最好方法就是使用它,所以我尝试在 IDLE 中实例化 NoneType:

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

现在很困惑,我做了一个快速的谷歌搜索。这表明 for some reason NoneType was somehow removed in Python 3.

不过,哈哈!我可以通过将 None 的类型存储在变量中来解决这个问题,因为 classes are objects in python.这似乎有效:

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

当我打印 n 时,我得到了我所期待的:

>>> print(n)
None

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

>>> n is None
True

和:

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

我的变量 nNone。不仅与 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
>>> 

更多错误。

这是我的问题:

  • 为什么 nNone 完全相同?
  • 为什么语言设计成 nNone 完全相同?
  • 如何在 Python 中实现这一行为?

最佳答案

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

尝试通过 type(None)() 创建 None 的实例是特殊情况,最终会调用 following C function :

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_NONEdefined here :

/*
_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

将此与 function that creates a normal python object 进行对比:

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 的每个引用都将是完全相同的对象。

关于python - NoneType 的实现、原因和细节,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20833081/

相关文章:

python - 当用户注销 Django 时如何删除 session ?

python - 动态地将数组中的值分配给字典

java - 这是单例延迟初始化吗?

javascript - Greensock TimelineMax Javascript 单例在 Firefox 中有所不同

python - “张量”对象没有属性 'lower'

python - Django 应用程序的用法是什么?

python - 一种在累积和变大的数组中查找索引的快速 numpy 方法?

python - 此代码中赋值前引用的变量

python-3.x - Python3 中使用 Gtk 和 XLib 的全局热键

android - 在 Android/Java 中将全局对象实现为单例或 DataClass 的优缺点