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 AttributeError
s 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:
n
the exact same Object as None
?n
is the exact same Object as None
?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.
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 .
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!
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With