Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implementation of NoneType, Reasons and Details

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, since most errors involving None in python produce AttributeErrors instead of some special "NoneError" or something.

Since all of these AttributeErrors reflected the attributes that NoneType lacked, I became intrigued by what attributes NoneType did have, if any.

I decided to look into this NoneType and learn more about it. I've always found the best way to learn about a new language feature is to use it, so I tried instantiating NoneType in IDLE:

>>> n = NoneType()

This produced an error:

Traceback (most recent call last):
File "<pyshell#0>", line 1, in <module>
    n = NoneType()
NameError: name 'NoneType' is not defined

Confused, I inspected None to see if I'd gotten the type name correct. Sure enough,

>>> type(None)
<class 'NoneType'>

Now very confused, I did a quick google search. This revealed that for some reason NoneType was somehow removed in Python 3.

Well I though, ha ha! I can work around this by storing the type of None in a variable, since classes are objects in python. This seemed to work:

>>> NoneType = type(None)
>>> n = NoneType()

And when I printed n, I got pretty much what I was expecting:

>>> print(n)
None

But then this happened:

>>> n is None
True

And:

>>> id(n)
506768776
>>> id(None)
506768776

My variable n IS None. Not only the same type as None. It IS None. This is not what I expected.

I tried using dis to get more info on NoneType, but when I called

>>> dis.dis(type(None))

It produced no output.

I then then tried investigating the __new__ method, which several users had mentioned in the comments:

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

More errors.

Here are my questions:

  • Why is n the exact same Object as None?
  • Why was the language designed such that n is the exact same Object as None?
  • How would one even implement this behavior in python?
like image 461
ApproachingDarknessFish Avatar asked Dec 30 '13 03:12

ApproachingDarknessFish


People also ask

What causes NoneType?

Some of the most common sources of None values are: Calling a function that does not return anything. Calling a function that sets the value of the data to None . Setting a variable to None explicitly.

What is the use of NoneType in Python?

NoneType in Python is a data type that simply shows that an object has no value/has a value of None . You can assign the value of None to a variable but there are also methods that return None .

How is None implemented in Python?

Python uses the keyword None to define null objects and variables. While None does serve some of the same purposes as null in other languages, it's another beast entirely. As the null in Python, None is not defined to be 0 or any other value. In Python, None is an object and a first-class citizen!

Why is Python saying my list is NoneType?

Sometimes this error appears when you forgot to return a function at the end of another function and passed an empty list, interpreted as NoneType.


2 Answers

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.

like image 29
Jake Cobb Avatar answered Sep 22 '22 14:09

Jake Cobb


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.

like image 128
user35147863 Avatar answered Sep 18 '22 14:09

user35147863