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