Bools and explicitness [was Re: PyWart: The problem with "print"]
Steven D'Aprano
steve+comp.lang.python at pearwood.info
Tue Jun 4 01:39:59 EDT 2013
On Mon, 03 Jun 2013 18:37:24 -0700, Rick Johnson wrote:
> On Sunday, June 2, 2013 1:58:30 PM UTC-5, Steven D'Aprano wrote:
>> On Sun, 02 Jun 2013 10:04:00 -0700, Rick Johnson wrote:
>> > A "wise programmer" may think he's solved the problem by writing a
>> > function called "debugprint" that looks like this:
>> > > def debugprint(*args):
>> > if DEBUG == True:
>> > print(*args)
>>
>> No no no, that's not how you do it. It should be:
>> if DEBUG == True == True:
>>
>> Wait, no, I got that wrong. It should be:
>> if DEBUG == True == True == True:
>>
>> Hang on, I've nearly got it!
>> if DEBUG == True == True == True == True:
>>
>> Or, you could program like a professional, and say:
>> if DEBUG:
>
> Obviously you don't appreciate the value of "explicit enough".
>
> if VALUE:
>
> is not explicit enough, however
Consider a simple thought experiment. Suppose we start with a sequence of
if statements that begin simple and get more complicated:
if a == 1: ...
if a == 1 and b > 2*c: ...
if a == 1 and b > 2*c or d%4 == 1: ...
if a == 1 and b > 2*c or d%4 == 1 and not (d**3//7)%3 == 0: ...
I don't believe that any of these tests are improved by adding an
extraneous "== True" at the end:
if (a == 1) == True: ...
if (a == 1 and b > 2*c) == True: ...
if (a == 1 and b > 2*c or d%4 == 1) == True: ...
if (a == 1 and b > 2*c or d%4 == 1 and not (d**3//7)%3 == 0) == True: ...
At some point your condition becomes so complicated that you may wish to
save it as a separate variable, or perhaps you need to check the flag in
a couple of places and so calculate it only once. Moving the flag out
into a separate variable doesn't make "== True" any more useful or
helpful.
flag = a == 1
if flag == True: ...
But even if it did, well, you've just entered the Twilight Zone, because
of course "flag == True" is just a flag, so it too needs to be tested
with "== True":
flag = (a == 1) == True
if flag == True: ...
but that too is just a flag so it needs more "explicitness"... and so on
forever. This conclusion is of course nonsense. Adding "== True" to your
boolean tests isn't helpful, so there's no need for even one, let alone
an infinite series of "== True".
"if flag" is as explicit as it needs to be. There's no need to
artificially inflate the "explicitness" as if being explicit was good in
and of itself. We don't normally write code like this:
n += int(1)
just to be explicit about 1 being an int. That would be redundant and
silly. In Python, 1 *is* an int.
[...]
> if lst:
>
> I don't like that because it's too implict. What exactly about the list
> are we wanting to test?
If you are unfamiliar with Python, then you have to learn what the
semantics of "if lst" means. Just as you would have to learn what
"if len(lst) > 0" means.
> I prefer to be explicit at the cost of a few keystrokes:
>
> if len(lst) > 0:
This line of code is problematic, for various reasons:
- you're making assumptions about the object which are unnecessary;
- which breaks duck-typing;
- and risks doing too much work, or failing altogether.
You're looking up the length of the lst object, but you don't really care
about the length. You only care about whether there is something there or
not, whether lst is empty or not. It makes no difference whether lst
contains one item or one hundred million items, and yet you're asking to
count them all. Only to throw that count away immediately!
Looking at the length of a built-in list is cheap, but why assume it is a
built-in list? Perhaps it is a linked list where counting the items
requires a slow O(N) traversal of the entire list. Or some kind of lazy
sequence that has no way of counting the items remaining, but knows
whether it is exhausted or not.
The Python way is to duck-type, and to let the lst object decide for
itself whether it's empty or not:
if lst: ...
not to make assumptions about the specific type and performance of the
object.
> Consider the following:
>
> What if the symbol `value` is expected to be a list, however, somehow
> it accidentally got reassigned to another type. If i choose to be
> implicit and use: "if value", the code could silently work for a type i
> did not intend, therefore the program could go on for quite some time
> before failing suddenly on attribute error, or whatever.
`if len(lst) > 0` also works for types you don't intend. Any type that
defines a __len__ method which returns an integer will do it.
Tuples, sets and dicts are just the most obvious examples of things that
support len() but do not necessarily support all the things you might
wish to do to a list.
> However, if i choose to be explicit and use:
>
> "if len(VALUE) > 0:
>
> then the code will fail when it should: at the comparison line.
Except of course when it doesn't.
> Because
> any object that does not provide a __len__ method would cause Python to
> raise NameError.
TypeError.
> By being "explicit enough" i will inject readability and safety into my
> code base.
Unnecessary verbosity and redundancy, unnecessary restrictions on the
type of the object, and unjustifiable assumptions about the cost of
calling len().
--
Steven
More information about the Python-list
mailing list