我最近在某处读过None
python 中的特殊值是它自己类的单例对象,具体来说NoneType
.这解释了很多,因为涉及None
python的大多数错误产生AttributeError
s而不是某些特殊的"NoneError"或其他东西.
由于所有的这些AttributeErrors
反映了属性的NoneType
缺乏,我开始用什么属性感兴趣NoneType
并如有有.
我决定研究这个NoneType
并了解更多相关信息.我总是发现学习新语言功能的最佳方法是使用它,所以我尝试NoneType
在IDLE中实例化:
>>> n = NoneType()
这产生了一个错误:
Traceback (most recent call last): File "", line 1, in n = NoneType() NameError: name 'NoneType' is not defined
困惑,我检查None
了我是否得到了正确的类型名称.果然,
>>> type(None)
现在非常困惑,我做了一个快速的谷歌搜索.这表明由于某些原因,在Python 3中以某种方式删除了NoneType.
好吧,不过,哈哈!我可以通过None
在变量中存储类型来解决这个问题,因为类是python中的对象.这似乎有效:
>>> NoneType = type(None) >>> n = NoneType()
当我打印n时,我得到的是我所期待的:
>>> print(n) None
但后来发生这种情况:
>>> n is None True
和:
>>> id(n) 506768776 >>> id(None) 506768776
我的变量n
IS None
.不仅是同一类型None
.它是None
.这不是我的预期.
我尝试使用dis
以获取更多信息NoneType
,但是当我打电话时
>>> dis.dis(type(None))
它没有产生任何产出.
然后我尝试调查这个__new__
方法,几个用户在评论中提到过:
dis.dis(type(None).__new__) Traceback (most recent call last): File "", line 1, in 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
完全相同的对象None
?
为什么设计的语言n
与Object完全相同None
?
如何在python中实现这种行为?
Narcolei.. 6
其他答案描述了如何用于__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
将是完全相同的对象。
其他答案描述了如何用于__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
将是完全相同的对象。