Python None comparison: should I use "is" or ==?
Question:
My editor warns me when I compare my_var == None
, but no warning when I use my_var is None
.
I did a test in the Python shell and determined both are valid syntax, but my editor seems to be saying that my_var is None
is preferred.
Is this the case, and if so, why?
Answers:
Summary:
Use is
when you want to check against an object’s identity (e.g. checking to see if var
is None
). Use ==
when you want to check equality (e.g. Is var
equal to 3
?).
Explanation:
You can have custom classes where my_var == None
will return True
e.g:
class Negator(object):
def __eq__(self,other):
return not other
thing = Negator()
print thing == None #True
print thing is None #False
is
checks for object identity. There is only 1 object None
, so when you do my_var is None
, you’re checking whether they actually are the same object (not just equivalent objects)
In other words, ==
is a check for equivalence (which is defined from object to object) whereas is
checks for object identity:
lst = [1,2,3]
lst == lst[:] # This is True since the lists are "equivalent"
lst is lst[:] # This is False since they're actually different objects
is
is generally preferred when comparing arbitrary objects to singletons like None
because it is faster and more predictable. is
always compares by object identity, whereas what ==
will do depends on the exact type of the operands and even on their ordering.
This recommendation is supported by PEP 8, which explicitly states that “comparisons to singletons like None should always be done with is
or is not
, never the equality operators.”
PEP 8 defines that it is better to use the is
operator when comparing singletons.
I recently encountered where this can go wrong.
import numpy as np
nparray = np.arange(4)
# Works
def foo_is(x=None):
if x is not None:
print(x[1])
foo_is()
foo_is(nparray)
# Code below raises
# ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
def foo_eq(x=None):
if x != None:
print(x[1])
foo_eq()
foo_eq(nparray)
I created a function that optionally takes a numpy array as argument and changes if it is included. If I test for its inclusion using inequality operators !=
, this raises a ValueError (see code above). If I use is not none
, the code works correctly.
We can take the list for example. Look here:
a = list('Hello')
b = a
c = a[:]
All have the same value:
['H', 'e', 'l', 'l', 'o']
['H', 'e', 'l', 'l', 'o']
['H', 'e', 'l', 'l', 'o']
is
refers to the actual memory slot, whether they are the specific object of interest:
print(a is b)
print(a is c)
Now we get the desired result.
True
False
PEP 8 also mentions this, saying "comparisons to singletons like None should always be done with is or is not, never the equality operators."
is
is also faster.
Another instance where "==" differs from "is". When you pull information from a database and check if a value exists, the result will be either a value or None.
Look at the if and else below. Only "is" works when the database returns "None". If you put == instead, the if statement won’t work, it will go straight to else, even though the result is "None". Hopefully, I am making myself clear.
conn = sqlite3.connect('test.db')
c = conn.cursor()
row = itemID_box.get()
# pull data to be logged so that the deletion is recorded
query = "SELECT itemID, item, description FROM items WHERE itemID LIKE '%" + row + "%'"
c.execute(query)
result = c.fetchone()
if result is None:
# log the deletion in the app.log file
logging = logger('Error')
logging.info(f'The deletion of {row} failed.')
messagebox.showwarning("Warning", "The record number is invalid")
else:
# execute the deletion
c.execute("DELETE from items WHERE itemID = " + row)
itemID_box.delete(0, tk.END)
messagebox.showinfo("Warning", "The record has been deleted")
conn.commit()
conn.close()
A useful tidbit to add to people’s understanding.
The reason that we check for identity with None
is because Python only ever stores the value None
in one place in memory, and every object which equals None
has its value stored in this same location. There are a handful of "special values" which get this treatment, and None
is just one of them.
But most values do not get this special treatment! For example, the float 1.25 can be stored in different locations in memory:
a = None
b = None
a is b
True
a = 1.25
b = 1.25
a is b
False
It just so happens that None
is among the handful of values which are always stored in one place in memory. Another example is any integer between -5
and 256
… since these integers are used often, they are always stored in memory, and every integer with that value is stored in the same place in your computer’s memory! Try it out:
a = 256
b = 256
a is b
True
a = 257
b = 257
a is b
False
So you can think of None
as being part of a special class of values which always have a constant memory address. That is why we can use is
to check whether two variables are both None
… it just checks whether the memory address is the same.
Edit: Joooeey makes the good point that which integers are stored in memory is specific to your python implementation, and the example of numbers from -5
to 256
is specific to CPython. If you don’t know what you’re running, it’s probably CPython, which is the most common implementation. But for this reason (and others) it is better practice to compare equality between these numbers with a == 2
and not with a is 2
. As for None
, it is specified to be the sole instance of the NoneType
type according to the Python Documentation itself, so regardless of implementation you can always compare it using a is None
.
My editor warns me when I compare my_var == None
, but no warning when I use my_var is None
.
I did a test in the Python shell and determined both are valid syntax, but my editor seems to be saying that my_var is None
is preferred.
Is this the case, and if so, why?
Summary:
Use is
when you want to check against an object’s identity (e.g. checking to see if var
is None
). Use ==
when you want to check equality (e.g. Is var
equal to 3
?).
Explanation:
You can have custom classes where my_var == None
will return True
e.g:
class Negator(object):
def __eq__(self,other):
return not other
thing = Negator()
print thing == None #True
print thing is None #False
is
checks for object identity. There is only 1 object None
, so when you do my_var is None
, you’re checking whether they actually are the same object (not just equivalent objects)
In other words, ==
is a check for equivalence (which is defined from object to object) whereas is
checks for object identity:
lst = [1,2,3]
lst == lst[:] # This is True since the lists are "equivalent"
lst is lst[:] # This is False since they're actually different objects
is
is generally preferred when comparing arbitrary objects to singletons like None
because it is faster and more predictable. is
always compares by object identity, whereas what ==
will do depends on the exact type of the operands and even on their ordering.
This recommendation is supported by PEP 8, which explicitly states that “comparisons to singletons like None should always be done with is
or is not
, never the equality operators.”
PEP 8 defines that it is better to use the is
operator when comparing singletons.
I recently encountered where this can go wrong.
import numpy as np
nparray = np.arange(4)
# Works
def foo_is(x=None):
if x is not None:
print(x[1])
foo_is()
foo_is(nparray)
# Code below raises
# ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
def foo_eq(x=None):
if x != None:
print(x[1])
foo_eq()
foo_eq(nparray)
I created a function that optionally takes a numpy array as argument and changes if it is included. If I test for its inclusion using inequality operators !=
, this raises a ValueError (see code above). If I use is not none
, the code works correctly.
We can take the list for example. Look here:
a = list('Hello')
b = a
c = a[:]
All have the same value:
['H', 'e', 'l', 'l', 'o']
['H', 'e', 'l', 'l', 'o']
['H', 'e', 'l', 'l', 'o']
is
refers to the actual memory slot, whether they are the specific object of interest:
print(a is b)
print(a is c)
Now we get the desired result.
True
False
PEP 8 also mentions this, saying "comparisons to singletons like None should always be done with is or is not, never the equality operators."
is
is also faster.
Another instance where "==" differs from "is". When you pull information from a database and check if a value exists, the result will be either a value or None.
Look at the if and else below. Only "is" works when the database returns "None". If you put == instead, the if statement won’t work, it will go straight to else, even though the result is "None". Hopefully, I am making myself clear.
conn = sqlite3.connect('test.db')
c = conn.cursor()
row = itemID_box.get()
# pull data to be logged so that the deletion is recorded
query = "SELECT itemID, item, description FROM items WHERE itemID LIKE '%" + row + "%'"
c.execute(query)
result = c.fetchone()
if result is None:
# log the deletion in the app.log file
logging = logger('Error')
logging.info(f'The deletion of {row} failed.')
messagebox.showwarning("Warning", "The record number is invalid")
else:
# execute the deletion
c.execute("DELETE from items WHERE itemID = " + row)
itemID_box.delete(0, tk.END)
messagebox.showinfo("Warning", "The record has been deleted")
conn.commit()
conn.close()
A useful tidbit to add to people’s understanding.
The reason that we check for identity with None
is because Python only ever stores the value None
in one place in memory, and every object which equals None
has its value stored in this same location. There are a handful of "special values" which get this treatment, and None
is just one of them.
But most values do not get this special treatment! For example, the float 1.25 can be stored in different locations in memory:
a = None
b = None
a is b
True
a = 1.25
b = 1.25
a is b
False
It just so happens that None
is among the handful of values which are always stored in one place in memory. Another example is any integer between -5
and 256
… since these integers are used often, they are always stored in memory, and every integer with that value is stored in the same place in your computer’s memory! Try it out:
a = 256
b = 256
a is b
True
a = 257
b = 257
a is b
False
So you can think of None
as being part of a special class of values which always have a constant memory address. That is why we can use is
to check whether two variables are both None
… it just checks whether the memory address is the same.
Edit: Joooeey makes the good point that which integers are stored in memory is specific to your python implementation, and the example of numbers from -5
to 256
is specific to CPython. If you don’t know what you’re running, it’s probably CPython, which is the most common implementation. But for this reason (and others) it is better practice to compare equality between these numbers with a == 2
and not with a is 2
. As for None
, it is specified to be the sole instance of the NoneType
type according to the Python Documentation itself, so regardless of implementation you can always compare it using a is None
.