Reputation: 9536
From what I've seen, the only time None
and False
behave differently is when they're compared to each other (for equality). Am I missing something, or is it ok to use only one or the other as long as you're consistent in your usage? Is there any reason to use one over the other?
Upvotes: 3
Views: 1163
Reputation: 6709
I would emphasize here the semantical difference rather than the behavioral.
Let's consider a couple of functions:
def find_user(criteria):
if is_met(criteria):
return User(...)
return None
# ...vs
def has_email(user):
return bool(user.email)
To me, in the above example, None
means an absence of the value, while False
means the boolean falsity.
An analogy here could be an emergence of the bool
type in C++. Historically, C (ab)used int
for boolean logic, but C++ introduced a dedicated bool
type which makes intentions behind some variables/function signatures clearer.
Upvotes: 7
Reputation: 2397
They are different types. Although, in practice, they behave quite similarly. You could also replace False
with: ""
, []
, (,)
or 0
and everything will mostly work. Python automatically converts your variable into a boolean whenever you pass it to if
, while
, to any boolean operators (eg. or
, and
, etc) or any builtin function expecting a boolean (side note: although or
, and and
do convert your value to boolean while deciding what to return, the end result will be your unconverted value). That's why it's difficult to tell the difference.
However, most developers will consider None
to be similar to a null
value in other languages, which is an error or unitialized value. Whilist False
will usually be considered an expected and fully initialized value. Therefore, it will be easier for most people to read your code if you stick to that convention.
Further elaborating that point, let's consider the C Python implementation. A typical if statement will be converted to the POP_JUMP_IF_FALSE
(or POP_JUMP_IF_TRUE
) instruction. This is how that is implemented:
TARGET(POP_JUMP_IF_FALSE) {
PyObject *cond = POP();
int err;
if (cond == Py_True) {
Py_DECREF(cond);
FAST_DISPATCH();
}
if (cond == Py_False) {
Py_DECREF(cond);
JUMPTO(oparg);
FAST_DISPATCH();
}
err = PyObject_IsTrue(cond);
Py_DECREF(cond);
if (err > 0)
;
else if (err == 0)
JUMPTO(oparg);
else
goto error;
DISPATCH();
}
As you can see, if the value passed to if
is a boolean the interpreter will know what to do right away. Otherwise, it will call PyObject_IsTrue, which will try to convert the object to a bool using any means possible (__bool__
, __nonzero__
, __len__
, and even comparing to None
explicitly).
Upvotes: 1
Reputation: 20490
If you are checking if a value is assigned or exists, you can use None
.
dct = {'key':'value'}
x = dct.get('key', None) # Get the value or get`None if it doesn't exist
def func(...):
if condition:
return Object()
return None
Whereas if you know the value will exist but want to check it's property, use False
if empty_list: #An empty list evaluates to `False`
do something
if not bool_var:
do something
Also bool(None)
evaluates to False
Upvotes: 0