class with __len__ member fools boolean usage "if x:" ; bad coding style?

Heiko Wundram heikowu at ceosg.de
Tue Jun 29 18:53:15 EDT 2004


Am Dienstag, 29. Juni 2004 20:34 schrieb Peter Otten:
> In Python, you don't normally check for a timeout (google for LBYL), you'd
> rather throw an exception. This avoids problems like
>
> h = Host()
> if h:
>    sleep(justLongEnoughForHostToTimeOut)
>    h.someOperation() # fails due to timeout

The operations on the host don't fail if the timeout has expired, in my use 
case. It's just that a host has a timeout, which signals the surrounding 
code, that this host needs to be contacted in the next run of ping signals.

What I can do to get these hosts now looks like the following:

ping_hosts = [h for h in hosts if not h]

That's what I call nice and concise, and at least for me the meaning is clear 
by just looking at the code. If the host has expired (not host), add it to 
the list of hosts to ping now.

> A __len__() without a __getitem__() method doesn't make sense to me. But
> maybe your example is just too terse...

Why should you need a __getitem__() if you have __len__() defined? In my use 
case, the ID (of a host/data-item, etc.) is not retrievable by single 
character (that would make no sense), but the length of the ID is 
significant, as it can signal important information as on the protocol to use 
to contact the host, etc.

So, I can how write:

someid = host
myid_old = myhost.old_id
myid_new = myhost.new_id

if len(someid) == 26:
	dist = myid_old ^ someid
elif len(someid) == 30:
	dist = myid_new ^ someid
else:
	raise ValueError, "Invalid host."

(where __xor__ is again a method defined on two IDs, returning the numerical 
distance, the binary xor between the two numbers)

I would never call this unintuitive, as in effect hosts are just IDs which 
have additional data (namely the IP/port pair), and can be used in any 
context in the program where IDs are wanted. And IDs can be asked for their 
length (to decide what to do with it). This doesn't just mean Hosts, also 
Data Items are IDs with additional data, which can be used just as well here.

> No amount of documentation can heal an unintuitive API.
> The convention of using bool(o) as an abbreviation of o.isValid() for
> non-sequences and of len(o) != 0 for sequences seems natural to me. Mixing
> these two meanings or even adding "was this parameter provided" as a third
> one will result in highly ambiguous code that is bound to break.

I can understand that in the normal case you would want to code something 
either as a sequence, or as a non-sequence. But, in this case, you have two 
classes, which have different use cases, but are derived from another (and 
deriving a Host from an ID isn't strange, at least for me). And for code 
which does something with the ID (and is specifically marked as such), it's 
pretty fair to use the ID part of the class which is passed in (which in this 
case are __len__ and __xor__) to make it concise, while where you use hosts, 
you take the host protocol to get at the host data (__nonzero__).

I don't see anything unintuitive in this... Actually, it makes the code look 
cleaner, IMHO.

Heiko.




More information about the Python-list mailing list