NoneType,原因和细节的实现

 摋無赦PK110_147 发布于 2023-02-07 15:57

我最近在某处读过Nonepython 中的特殊值是它自己类的单例对象,具体来说NoneType.这解释了很多,因为涉及Nonepython的大多数错误产生AttributeErrors而不是某些特殊的"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

我的变量nIS 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将是完全相同的对象。

1 个回答
  • 其他答案描述了如何用于__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将是完全相同的对象。

    2023-02-07 15:59 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有