Implementation of NoneType, Reasons and Details

后端 未结 4 1123
灰色年华
灰色年华 2021-01-11 15:53

I recently read somewhere that the special value None in python is a singleton object of its own class, specifically NoneType. This explained a lot

相关标签:
4条回答
  • 2021-01-11 16:26
    1. The NoneType overrides __new__ which always return the same singleton. The code is actually written in C so dis cannot help, but conceptually it's just like this.

    2. Having only one None instance is easier to deal with. They are all equal anyway.

    3. By overriding __new__... e.g.

      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)
      
    0 讨论(0)
  • 2021-01-11 16:32

    Why is n the exact same Object as None?

    Many immutable objects in Python are interned including None, smaller ints, and many strings.

    Demo:

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

    Why was the language designed such that n is the exact same Object as None?

    See above -- speed, efficiency, lack of ambiguity and memory usage among other reasons to intern immutable objects.

    How would one even implement this behavior in python?

    Among other ways, you can override __new__ to return the same object:

    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
    

    For strings, you can call intern on Python 2 or sys.intern on Python 3

    0 讨论(0)
  • 2021-01-11 16:33

    Other answers describe how to use __new__ to implement a singleton, but that's not how None is actually implemented (in cPython at least, I haven't looked into other implementations).

    Trying to create an instance of None through type(None)() is special cased, and ends up calling the 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;
    }
    

    And Py_RETURN_NONE is 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
    

    Contrast this with the 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);
    }
    

    When you create a normal object, memory for the object is allocated and initialized. When you try to create a new instance of None, all you get is a reference to the already existing _Py_NoneStruct. That's why, no matter what you do, every reference to None will be the exact same object.

    0 讨论(0)
  • 2021-01-11 16:38

    Why is n the exact same Object as None?

    The C implementation keeps a singleton instance. NoneType.__new__ is returning the singleton instance.

    Why was the language designed such that n is the exact same Object as None?

    If there was not a singleton instance, then you could not rely on the check x is None since the is operator is based on identity. Although None == None is also True, it's possible to have x == None be True when x is not actually None. See this answer for an example.

    How would one even implement this behavior in python?

    You can implement this pattern by overridding __new__. Here's a basic example:

    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)
    

    Output:

    s1 is s2: True
    id(s1): 4506243152
    id(s2): 4506243152

    Of course this simple example doesn't make it impossible to create a second instance.

    0 讨论(0)
提交回复
热议问题