Why Is "If Not Someobj:" Better Than "If Someobj == None:" in Python

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 :

  1. If the object has a __nonzero__ special method (as do numeric built-ins, int and float), it calls this method. It must either return a bool value which is then directly used, or an int value that is considered False if equal to zero.

  2. Otherwise, if the object has a __len__ special method (as do container built-ins, list, dict, set, tuple, ...), it calls this method, considering a container False if it is empty (length is zero).

  3. Otherwise, the object is considered True unless it is None in which case, it is considered False.

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 :

  1. If the object has a __eq__ method, it is called, and the return value is then converted to a boolvalue and used to determine the outcome of the if.

  2. Otherwise, if the object has a __cmp__ method, it is called. This function must return an int indicating the order of the two object (-1 if self < other, 0 if self == other, +1 if self > other).

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



Leave a reply



Submit