App*_*ish 9 python singleton python-3.x python-internals nonetype
我最近在某处读过Nonepython 中的特殊值是它自己类的单例对象,具体来说NoneType.这解释了很多,因为涉及Nonepython的大多数错误产生AttributeErrors而不是某些特殊的"NoneError"或其他东西.
由于所有的这些AttributeErrors反映了属性的NoneType缺乏,我开始用什么属性感兴趣NoneType 并如有有.
我决定研究这个NoneType并了解更多相关信息.我总是发现学习新语言功能的最佳方法是使用它,所以我尝试NoneType在IDLE中实例化:
>>> n = NoneType()
Run Code Online (Sandbox Code Playgroud)
这产生了一个错误:
Traceback (most recent call last):
File "<pyshell#0>", line 1, in <module>
n = NoneType()
NameError: name 'NoneType' is not defined
Run Code Online (Sandbox Code Playgroud)
困惑,我检查None了我是否得到了正确的类型名称.果然,
>>> type(None)
<class 'NoneType'>
Run Code Online (Sandbox Code Playgroud)
现在非常困惑,我做了一个快速的谷歌搜索.这表明由于某些原因,在Python 3中以某种方式删除了NoneType.
好吧,不过,哈哈!我可以通过None在变量中存储类型来解决这个问题,因为类是python中的对象.这似乎有效:
>>> NoneType = type(None)
>>> n = NoneType()
Run Code Online (Sandbox Code Playgroud)
当我打印n时,我得到的是我所期待的:
>>> print(n)
None
Run Code Online (Sandbox Code Playgroud)
但后来发生这种情况:
>>> n is None
True
Run Code Online (Sandbox Code Playgroud)
和:
>>> id(n)
506768776
>>> id(None)
506768776
Run Code Online (Sandbox Code Playgroud)
我的变量nIS None.不仅是同一类型None.它是None.这不是我的预期.
我尝试使用dis以获取更多信息NoneType,但是当我打电话时
>>> dis.dis(type(None))
Run Code Online (Sandbox Code Playgroud)
它没有产生任何产出.
然后我尝试调查这个__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
>>>
Run Code Online (Sandbox Code Playgroud)
更多错误.
这是我的问题:
n完全相同的对象None?n与Object完全相同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;
}
Run Code Online (Sandbox Code Playgroud)
而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
Run Code Online (Sandbox Code Playgroud)
将此与创建普通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);
}
Run Code Online (Sandbox Code Playgroud)
创建普通对象时,将分配并初始化该对象的内存。当您尝试创建的新实例时None,所获得的只是对已经存在的引用_Py_NoneStruct。这就是为什么无论您做什么,对每个引用都None将是完全相同的对象。
为什么是n完全相同的对象None?
C 实现保留了一个单例实例。 NoneType.__new__正在返回单例实例。
为什么将语言设计为 n 与 Object 完全相同None?
如果没有单例实例,那么您就不能依赖检查,x is None因为is操作符是基于身份的。虽然None == None也是True,它可能有x == None是True时候x实际上不是None。有关示例,请参阅此答案。
甚至如何在 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)
Run Code Online (Sandbox Code Playgroud)
输出:
s1 是 s2:真实
id(s1):4506243152
id(s2):4506243152
当然,这个简单的例子并没有使创建第二个实例成为不可能。
| 归档时间: |
|
| 查看次数: |
1623 次 |
| 最近记录: |