Backwards compatibility [was Re: is parameter an iterable?]

Alex Martelli aleax at mail.comcast.net
Mon Nov 21 22:11:02 EST 2005


Steven D'Aprano <steve at REMOVEMEcyber.com.au> wrote:
   ...
> In the specific case of iter(), are there good 
> alternative ways of detecting an iterable without 
> consuming it?

Not a problem I've had often, but when I did, if I recall correctly, I
did something like:

try:
  iter
except NameError:
  def isiterable(x):
    try: x[0]
    except Exception: return 0
    else: return 1
else:
  def isiterable(x):
    try: iter(x)
    except TypeError: return 0
    else: return 1

Not True/False because they wouldn't be available in 2.0 any more than
iter would.  "Consuming" didn't really come into consideration for the
backwards compatibility part because only objects indexable with
integers, 0 and up (and raising IndexError at some point) were usable in
for statements in old Pythons, there was no "consuming".  The tests here
are not 100% reliable, of course -- in 2.0, a dict which just happens to
have a 0 key would erroneously pass; but short of actually trying the
loop, there's no infallible way that I know of.

One possibility (that I haven't tried in real life) to deal with the
hellish situation of having to write code that's able to loop on an
iterable but fail softly otherwise, while not hiding errors in the
loop's body, would be the suitably hellish...:

class NotATypeError(Exception):
  def __init__(self, e, t):
    self.e = e
    self.t = t

try:
  try:
      for item in whatever:
          try:
              ...loop body here...
          except TypeError, e, t:
              raise NotATypeError(e, t)
  except TypeError:
      ....fail-softly code...
except NotATypeError, x:
  raise TypeError, x.e, x.t


This kind of spaghetti code is what gives backwards compatibility its
bad name, of course.  Be sure that you're getting paid for this in
proportion to its ugliness, and your finances should be set for life.


Alex



More information about the Python-list mailing list