Implicit conversion to boolean in if and while statements

Steven D'Aprano steve+comp.lang.python at pearwood.info
Tue Jul 17 06:39:33 CEST 2012


On Mon, 16 Jul 2012 20:57:43 -0500, Andrew Berg wrote:

> I have a better real example, but I opted not to use it before since it
> requires some explanation - IRC messages. A client-to-server message has
> the basic form of b'COMMAND arguments :message' (e.g. b'PRIVMSG #channel
> :hi guys!'). Some commands have no message part because there is no
> message associated with it (e.g. b'JOIN #channel') and there is at least
> one where there is a big difference between a blank message (b'') and no
> message - b'TOPIC #channel' is a request for the topic while b'TOPIC
> #channel :' clears the topic since the part after the b':' is b''
> (b'TOPIC #channel :Welcome to #channel' sets the topic to "Welcome to
> #channel"). 

Okay, so you have two distinct "nothing" states when considering the 
message part of an IRC command: the empty string, and missing.

That's okay. Floats have two zeroes (+0.0 and -0.0); complex numbers have 
four. (Although they try hard to hide that distinction from you.)

There's nothing that says that you can only have a single falsey value in 
a type, or that you might not sometimes wish to distinguish between 
different false-like states. You need to distinguish between the many 
different true-like messages, so you should not be surprised that you 
need to distinguish between two false-like messages.

There are many ways to implement this. Here are just the most obvious:

1) a Command object where the message attribute is optional, but if
   present, it is always a string;

2) a Command object where the message attribute is always present, but
   can be a string or some non-string sentinel value (e.g. None);

3) a string, where the message attribute is determined by the location
   of the colon, if any

4) a tuple with either two or three fields: (command, channel [,message])



> In my code, I would have an object representing a message
> rather than parsing it multiple times. If the message
> attribute is not None, I send b'{command} {args} :{message}', otherwise
> b'{command} {args}'. 

Clear and obvious. Nothing wrong with that.


> I could do:
> 
> if has_message:
> 	send('{command} {args} :{message}')
> else:
> 	send('{command} {args}')
> 
> but then I'd have to make sure has_message stays accurate since message
> won't necessarily be. 

Yes, keeping a separate variable is a mug's game. Encapsulate it in the 
Command object, and have the Command object responsible for keeping it in 
sync (assuming it is mutable), or just make Command immutable and be done 
with it.


> Or maybe I could leave message undefined and catch
> the appropriate exception. However, using None is the cleanest and most
> obvious.

Yes it is. What's your point?

You've discovered a real-world situation where you can't collapse the 
entire universe of valid values into just two, True and False, without 
losing information. Did you think that this would be surprising?

Python developers often talk about interpreting objects "in a boolean 
context" -- that's a pretty big hint that the semantics are to collapse 
the value into two states. If you need three (or four, or fifty) 
distinguishable states, then obviously boolean context will not solve 
your problem. I never said it would.



-- 
Steven



More information about the Python-list mailing list