我最近在某处读到python中的特殊值None
是其自己的类的单个对象,特别是NoneType
。这解释了很多,因为python中涉及None
的大多数错误产生AttributeError
而不是某些特殊的“NoneError”或其他东西。
由于所有这些AttributeErrors
都反映了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
我的变量n
是None
。不仅与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
与None
完全相同的对象?n
与None
完全相同?答案 0 :(得分:4)
其他答案描述了如何使用__new__
来实现单例,但实际上并没有实现None(至少在cPython中,我没有考虑其他实现)。
尝试通过type(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_NONE
是defined 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
的引用都将是完全相同的对象。
答案 1 :(得分:2)
为什么n
与None
完全相同?
C实现保留单例实例。 NoneType.__new__
正在返回单例实例。
为什么设计的语言使得n与None
完全相同?
如果没有单例实例,那么您不能依赖检查x is None
,因为is
运算符基于身份。虽然None == None
也是True
,但x == None
实际上不是True
时,x
可能会None
。有关示例,请参阅this answer。
如何在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
当然,这个简单的例子并没有让不可能来创建第二个实例。
答案 2 :(得分:0)
NoneType覆盖__new__
,它总是返回相同的单例。代码实际上是written in C所以dis
无法帮助,但从概念上讲它就是这样。
只有一个None实例更容易处理。无论如何,它们都是平等的。
重写__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)
答案 3 :(得分:0)
为什么n与None完全相同?
Python中的许多不可变对象都是interned,包括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