Why is if not someobj: better than if someobj == None: in Python?
In the first test, Python try to convert the object to a bool
value if it is not already one. Roughly, we are asking the object : are you meaningful or not ? This is done using the following algorithm :
If the object has a
__nonzero__
special method (as do numeric built-ins,int
andfloat
), it calls this method. It must either return abool
value which is then directly used, or anint
value that is consideredFalse
if equal to zero.Otherwise, if the object has a
__len__
special method (as do container built-ins,list
,dict
,set
,tuple
, ...), it calls this method, considering a containerFalse
if it is empty (length is zero).Otherwise, the object is considered
True
unless it isNone
in which case, it is consideredFalse
.
In the second test, the object is compared for equality to None
. Here, we are asking the object, "Are you equal to this other value?" This is done using the following algorithm :
If the object has a
__eq__
method, it is called, and the return value is then converted to abool
value and used to determine the outcome of theif
.Otherwise, if the object has a
__cmp__
method, it is called. This function must return anint
indicating the order of the two object (-1
ifself < other
,0
ifself == other
,+1
ifself > other
).Otherwise, the object are compared for identity (ie. they are reference to the same object, as can be tested by the
is
operator).
There is another test possible using the is
operator. We would be asking the object, "Are you this particular object?"
Generally, I would recommend to use the first test with non-numerical values, to use the test for equality when you want to compare objects of the same nature (two strings, two numbers, ...) and to check for identity only when using sentinel values (None
meaning not initialized for a member field for exemple, or when using the getattr
or the __getitem__
methods).
To summarize, we have :
>>> class A(object):
... def __repr__(self):
... return 'A()'
... def __nonzero__(self):
... return False
>>> class B(object):
... def __repr__(self):
... return 'B()'
... def __len__(self):
... return 0
>>> class C(object):
... def __repr__(self):
... return 'C()'
... def __cmp__(self, other):
... return 0
>>> class D(object):
... def __repr__(self):
... return 'D()'
... def __eq__(self, other):
... return True
>>> for obj in ['', (), [], {}, 0, 0., A(), B(), C(), D(), None]:
... print '%4s: bool(obj) -> %5s, obj == None -> %5s, obj is None -> %5s' % \
... (repr(obj), bool(obj), obj == None, obj is None)
'': bool(obj) -> False, obj == None -> False, obj is None -> False
(): bool(obj) -> False, obj == None -> False, obj is None -> False
[]: bool(obj) -> False, obj == None -> False, obj is None -> False
{}: bool(obj) -> False, obj == None -> False, obj is None -> False
0: bool(obj) -> False, obj == None -> False, obj is None -> False
0.0: bool(obj) -> False, obj == None -> False, obj is None -> False
A(): bool(obj) -> False, obj == None -> False, obj is None -> False
B(): bool(obj) -> False, obj == None -> False, obj is None -> False
C(): bool(obj) -> True, obj == None -> True, obj is None -> False
D(): bool(obj) -> True, obj == None -> True, obj is None -> False
None: bool(obj) -> False, obj == None -> True, obj is None -> True
If not condition statement in python
if
is the statement. not start
is the expression, with not
being a boolean operator.
not
returns True
if the operand (start
here) is considered false. Python considers all objects to be true, unless they are numeric zero, or an empty container, or the None
object or the boolean False
value. not
returns False
if start
is a true value. See the Truth Value Testing section in the documentation.
So if start
is None
, then indeed not start
will be true. start
can also be 0
, or an empty list, string, tuple dictionary, or set. Many custom types can also specify they are equal to numeric 0 or should be considered empty:
>>> not None
True
>>> not ''
True
>>> not {}
True
>>> not []
True
>>> not 0
True
Note: because None
is a singleton (there is only ever one copy of that object in a Python process), you should always test for it using is
or is not
. If you strictly want to test tat start
is None
, then use:
if start is None:
Difference between if not: and if False:
In python (and other dynamic languages) there is the concept of truthy/falsy value. True/False
are not the only things that evaluate as true/false
if not []:
print('this will be printed')
if [] is False:
print('this won't)
Another problem is that you should compare with x == False
, and not x is False
. The False
is a singleton object in the current implementation of CPython, but this is not guaranteed by the specification.
Why does 'if not None' return True?
In Python None
is a singleton. It is called the null
in other languages.
In your if not None:
, the compiler assumes that not None means non empty, or non-zero and we know an if statement evaluates non-zero values as True
and executes them.
Function Examples:
1) if not None:
prints argument x in test()
def test(x):
if not None:
print(x)
>>> test(2)
2
2) if 1:
prints argument x in test()
def test(x):
if 1:
print(x)
>>> test(2)
2
3) if -1:
prints argument x in test()
def test(x):
if -1:
print(x)
>>> test(2)
2
4) if 0:
does not prints argument x in test()
def test(x):
if 0:
print(x)
>>> test(2)
5) if True:
prints argument x in test()
def test(x):
if True:
print(x)
>>> test(2)
2
Python 'If not' syntax
Yes, if bar is not None
is more explicit, and thus better, assuming it is indeed what you want. That's not always the case, there are subtle differences: if not bar:
will execute if bar
is any kind of zero or empty container, or False
.
Many people do use not bar
where they really do mean bar is not None
.
Checking whether something is iterable
The proper way to check for iterability is as follows:
function isIterable(obj) {
// checks for null and undefined
if (obj == null) {
return false;
}
return typeof obj[Symbol.iterator] === 'function';
}
Why this works (iterable protocol in depth): https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Iteration_protocols
Since we are talking about for..of, I assume, we are in ES6 mindset.
Also, don't be surprised that this function returns true
if obj
is a string, as strings iterate over their characters.
Python and is not None
The boolean expressions in your if
are short-circuit evaluated left to right. What is wrong in your code is that you are applying the is not None
condition after you have used the object. You need to invert the order of the conditions.
if fundbenchmark is not None and not fundbenchmark.endswith(("Index", "INDEX")):
What is the purpose and use of **kwargs?
You can use **kwargs
to let your functions take an arbitrary number of keyword arguments ("kwargs" means "keyword arguments"):
>>> def print_keyword_args(**kwargs):
... # kwargs is a dict of the keyword args passed to the function
... for key, value in kwargs.iteritems():
... print "%s = %s" % (key, value)
...
>>> print_keyword_args(first_name="John", last_name="Doe")
first_name = John
last_name = Doe
You can also use the **kwargs
syntax when calling functions by constructing a dictionary of keyword arguments and passing it to your function:
>>> kwargs = {'first_name': 'Bobby', 'last_name': 'Smith'}
>>> print_keyword_args(**kwargs)
first_name = Bobby
last_name = Smith
The Python Tutorial contains a good explanation of how it works, along with some nice examples.
Python 3 update
For Python 3, instead of iteritems()
, use items()
Related Topics
What's the Best Way to Return Multiple Values from a Function
Pandas Column Access W/Column Names Containing Spaces
Getting an Instance Name Inside Class _Init_()
Quick Way to Upsample Numpy Array by Nearest Neighbor Tiling
Convert Decimal Mark When Reading Numbers as Input
A Mutable Type Inside an Immutable Container
Is There a Python Equivalent of the C# Null-Coalescing Operator
How to Do Multiple Substitutions Using Regex
Fastapi Runs API-Calls in Serial Instead of Parallel Fashion
Django HTML Template Can't Find Static CSS and Js Files
I Don't Understand This Python _Del_ Behaviour