if var:
...
is better code (for my value of better, which is subjective) than: if var is not None:
... if var:
...
is better code (for my value of better, which is subjective) than: if var is not None:
...Testing for "not None" also immediately tells other devs at least something about what's going on. Example: If var is an argument to a function and you see "if var," really understanding what's going on means looking at all invocations of that function to see what's being passed in.
Further, in that scenario, it's possible that different types are being passed for that argument. While "if var" could make this work where "if var is not None" would break functionality, in my opinion, it should break. Without getting into arguments about static typing, "truthiness" allows both sloppy code and the accidental introduction of bugs that might otherwise be caught during development due to faulty logic from vague conditional checks.
http://en.wikipedia.org/wiki/Principle_of_least_astonishment
if var in (None, 0, "", [], {}, ...):
pass
something like that?In general, most of those false-y values make sense. Midnight being a false-y value does not make sense. This seems to be a case of "we represent midnight as zero internally, and zero is false-y, so midnight should be false-y." This logic does not make sense to me. If they represented noon as 0 instead, should that evaluate to false, just because?
I agree that midnight evaluating to false is ridiculous (I wasn't aware of this, thankfully I've never run into it). I'm not sure where you got the idea that I support this, but I don't.
def __bool__(self):
if self.second or self.microsecond:
return True
offset = self.utcoffset() or timedelta(0)
return timedelta(hours=self.hour, minutes=self.minute) != offset
http://hg.python.org/cpython/file/302c8fdb17e3/Lib/datetime....Now that I look at the actual code, it makes less sense. It's not just midnight that evaluates to False. It's midnight UTC that evals to False. So if your timezone is PST, then 8AM evals to False. Since most datetime.time() objects are timezone 'dumb' by default, this distinction doesn't matter so much, but I can see this still biting some people hard, even if "Midnight is false-y" made sense.
Edit: Also, to the "explicit is better than implicit" crowd, notice this line (in core libs):
if self.second or self.microsecond:
return True
It's not: if self.second != 0 or self.microsecond != 0:
return True
What could be more 'Pythonic' than the Python core libraries?Edit: s/EST/PST/ ^^;;
self foo isNil ifTrue: [self defaultFoo]
later some implementations added a method on object to test for nil
self foo ifNil: [self defaultFoo]
if you had to test for nil before testing for a condition it would be a bit ugly.
self foo ifNil: [((self foo) isFooish) ifTrue: [self defaultFoo]]
In ruby which was developed about a bit later perhaps to late to influence pythons bool handling they got rid of this problem by treating either nil or false as Falsey and everything else as truthy.
In python everything is true except:
None
False
zero of any numeric type, for example, 0, 0L, 0.0, 0j.
any empty sequence, for example, '', (), [].
any empty mapping, for example, {}.
instances of user-defined classes, if the class defines a __nonzero__() or __len__() method, when that method returns the integer zero or bool value False. [1]
http://docs.python.org/2/library/stdtypes.html
In python 3 __nonzero__ is __bool__
The reason for 0 being a truthy value arguably is arguably due to historical reasons. false used to be 0 and truth used to be 1, when they introduced a bool type they made it be an integer.
Some of the important python people(who are much better programmers then me) may disagree(http://stackoverflow.com/a/3175293/259130) but I think
it was a ugly stain and should have been removed in python3 along with the whole 0(of any numeric type) being falsey.The upside to python behaving like this is that in many situations you don't care what kind of falsey value you may have and you can write
if person and person.name: instead of if person != None and person.name != None and person.name != "":
and
if students and "John" in students and students[John"].age and students[John"].friends: print "John has friends" instead of if students != None and "John" in students and students[John"].age != None and len(students[John"].friends) > 0: print "John has friends"
There are downsides to this and people may have a strong personal preference for personal scripts and you can argue that the ruby way or even the smalltalk way is conceptually nicer(and more "explicit") but this is proper pythonic style and generally you should use it in python(maybe not the numerical one except when getting len of a collection)(unless you specifically depend on different code for different falsey values).
I suppose the hilarious way to argue it would be to say that there is an implicit "all other things being equal" in front of each of those.
All other things being equal, I see no reason to write code that needlessly introduces potential bugs and maintainability issues by ignoring the rule of thumb that explicit trumps implicit.
The documentation is pretty clear about it:
http://docs.python.org/release/3.3.4/library/stdtypes.html#t...
Which leads to this:
>>> a=object()
>>> bool(a)
True
>>> if var:
...
is better in some situations, but is objectively worse in many others. If you really do want anything that's "falsey" to fall into that conditional, then by all means, use it! Just be aware that `0`, `[]`, `None`, `0.0`, etc will all be treated the same.However, it's harmful in one of its most common use cases: default values.
For example, let's say you're working with a function that takes an optional argument similar to:
def foo(x, values=None):
if values is None:
values = []
You shouldn't use a mutable default argument for several reasons, so instead you make the default "None" and set it to an empty sequence. The snippet above is the standard idiom.Let's say a user mistakenly passes "values=0" instead of "values=[0]".
If you had done:
if not values:
values = []
Then the code will happily proceed with "values" being an empty list and _silently give incorrect output_ instead of raising an error a couple of lines later.You can make the (very reasonable) argument that this is all the fault of dynamic typing, and if python was just a staticly typed language, the compiler would catch all of this, but that's beside the point.
Be aware of what you're testing if you choose "if var:" instead of "if var is not None:"
I didn't argue, and certainly didn't mean to imply, that it is always better, but in the sort of case we're considering in this example, i.e. we expect a valid time value or None, It really is madness to imply a time value of midnight is "empty".
From PEP-8: http://legacy.python.org/dev/peps/pep-0008/
You could argue that the python is badly designed in this case and that the two should be equivalent, but that's a different argument.
(For certain types, they do have the same behavior. In those cases, the subjective question is fine. But times are not a case where the behavior is the same.)
Explicit is better than implicit.
This has now proven to be false, and python is starting to add optional type annotations. It's not practical to introduce static typing more quickly - it would break too many existing programs.
The latter seems a lot less common and surprising.
if var is not None:
...