Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Strings and the and operator: best practice, differences with +

Tags:

python

For one of my sites, I need to check if several class attributes are defined and not empty. So far, I've happily used if self.attr:, which in my mind is the shorthand for if self.attr is not None and self.attr is not '':, or whatever the undefined value of the attribute is.

This works fine, but yields to surprising behavior when checking multiple string attributes. '' and '' is not False (as I expected), but ''.

This begs the question: are there other types for which the and operator does not force a typecast to bool? I can't come up with an example where this difference in behavior would cause an actual different outcome for the if-clause (after all, '' still evaluates to False), but am left with the gut feeling that there's edge cases that could be a trap.

Lastly, I'd be keen to know if anybody knows why it was implemented that way? I thought the Zen of Python encourages one way and one way only, and the + operator already seems to bethe intuitive way for string concatenation.

like image 315
Maik Hoepfel Avatar asked Aug 07 '12 12:08

Maik Hoepfel


1 Answers

and never typecasts to bool. Rather, if calls bool() on the result of expressions.

An expression using and (and or, for that matter), short-circuits when it can determine that the expression will not evaluate to True or False based on the first operand, and returns the last evaluated value:

>>> 0 and 'string'
0
>>> 1 and 'string'
'string'
>>> 'string' or 10
'string'
>>> '' or 10
10

This 'side-effect' is often used in python code. Note that not does return a boolean value. See the python documentation on boolean operators for the details.

The documentation also explains what constitutes a True or False equivalent for various types, such as None, 0, '' and empty containers being False, while most everything else is equivalent to True.

For custom classes, you need to define the .__nonzero__() method (returns True or False) or a .__len__() method (returns an int, where 0 is False and everything else is True), to influence their boolean equivalent, otherwise they'll always default to True.

like image 157
Martijn Pieters Avatar answered Nov 15 '22 15:11

Martijn Pieters