9

Is it safe to check whether a variable myvar has not-None value by simply:

if myvar:
    print('Not None detected')

I'm asking this because I have a variable and was checking whether the variable was not None by simply if variable: but the check has been failing. The variable contains some data but it was evaluating to False in the if check.

Full Code:

from xml.etree import ElementTree as ElementTree

root = ElementTree.fromstring('Some xml string')

parameters = root.find('Some Tag')

udh = parameters.find('UDH')

if udh and udh.text:  # In this line the check is failing, though the udh variable has value: <Element 'UDH' at 0x7ff614337208>
    udh = udh.text
    # Other code
else:
    print('No UDH!')  # Getting this output
Shafiul
  • 2,832
  • 9
  • 37
  • 55
  • This is actually wrong. ``if myvar:`` assuming ``myvar`` is ``None`` will actually not evaluate to ``True`` and therefore your sample won't work. It is however best practice to use the form: ``if myvar is not None:`` or ``if myvar is None:`` – James Mills May 12 '14 at 07:25
  • Was answered here: http://stackoverflow.com/questions/3965104/not-none-test-in-python – vladfau May 12 '14 at 07:25
  • Isn't your check failing because there's no text in udh? It could be an empty XML node. – Midnighter May 12 '14 at 08:31
  • @Midnighter I'm sure I've text in my udh node. – Shafiul May 13 '14 at 04:24
  • @Midnighter but it does not have any child node. Could that be a possibility for being evaluated as False? – Shafiul May 13 '14 at 15:09

3 Answers3

7

In Python the boolean (truth) value of the object is not necessarily equal to being None or not. The correctness of that assumption depends on whether your object has the correct methods defined appropriately. As for Python 2.7:

object.__nonzero__(self)

Called to implement truth value testing and the built-in operation bool(); should return False or True, or their integer equivalents 0 or 1. When this method is not defined, __len__() is called, if it is defined, and the object is considered true if its result is nonzero. If a class defines neither __len__() nor __nonzero__(), all its instances are considered true.

Also have a look at the PEP 8, that provides guidance for this issue (emphasis mine):

Comparisons to singletons like None should always be done with is or is not, never the equality operators.

Also, beware of writing if x when you really mean if x is not None -- e.g. when testing whether a variable or argument that defaults to None was set to some other value. The other value might have a type (such as a container) that could be false in a boolean context!

Therefore, to safely test whether you've got None or not None you should use specifically:

if myvar is None: 
    pass
elif myvar is not None:
    pass

In the case of the xml.etree.ElementTree.Element the semantics of the boolean evaluation differ from the None-ness of the object:

For reference:

Community
  • 1
  • 1
moooeeeep
  • 31,622
  • 22
  • 98
  • 187
  • 3
    [pep 8](http://legacy.python.org/dev/peps/pep-0008/#programming-recommendations) has a word on this too: *Also, beware of writing ``if x`` when you really mean ``if x is not None``* – Jonas Schäfer May 12 '14 at 07:44
  • Thanks a lot for your answer. Can you tell what happens in Python 3 for evaluating whether a value referred by a variable can be Boolean? – Shafiul May 13 '14 at 04:42
  • 1
    @giga Have a look at this for truth value testing in Python 3: https://docs.python.org/3/library/stdtypes.html#truth-value-testing – moooeeeep May 13 '14 at 09:05
3

The ElementTree behaviour for nodes without children is a notorious departure from standard Python practice. In general, it'd be safe to just use the variable in your if condition and assume that the boolean value is sensible. In this case, as you've experienced first hand, you'll have to do a more explicit check.

Noufal Ibrahim
  • 71,383
  • 13
  • 135
  • 169
2

For your case, it is safe since ElementTree returns False to the __nonzero__ test to check if the element has been found or not.

However, as the doc says, it is better to check explicitly, with is None if you want to check only if the element hasn't been found:

Caution: Because Element objects do not define a nonzero() method, elements with no subelements will test as False.

element = root.find('foo')

if not element: # careful!
    print "element not found, or element has no subelements"

if element is None:
    print "element not found"

For reminder, object.__nonzero__ is used in value testing and in the bool() operation.

Community
  • 1
  • 1
Maxime Lorant
  • 34,607
  • 19
  • 87
  • 97