Conditionally implementing __iter__ in new style classes

Bengt Richter bokr at oz.net
Wed Jul 6 13:03:04 EDT 2005


On Wed, 06 Jul 2005 17:57:42 +0200, Thomas Heller <theller at python.net> wrote:

>I'm trying to implement __iter__ on an abstract base class while I don't
>know whether subclasses support that or not.
>Hope that makes sense, if not, this code should be clearer:
>
>class Base:
>    def __getattr__(self, name):
>        if name == "__iter__" and hasattr(self, "Iterator"):
>            return self.Iterator
>        raise AttributeError, name
>
>class Concrete(Base):
>    def Iterator(self):
>        yield 1
>        yield 2
>        yield 3
>
>The idea is that if a subclass of Base defines an 'Iterator' method,
>instances are iterable.  They are not iterable otherwise.
>
>The above gives the expected behaviour: iter(Base()) raises a
>"TypeError: iteration over non-sequence", and iter(Concrete()) returns a
>generator.
>
>If, however, I make Base a newstyle class, this will not work any
>longer.  __getattr__ is never called for "__iter__" (neither is
>__getattribute__, btw).  Probably this has to do with data descriptors
>and non-data descriptors, but I'm too tired at the moment to think
>further about this.
>
>Is there any way I could make the above code work with new style
>classes?
Will a property or custom descriptor do what you want? E.g.

 >>> class Base(object):
 ...     def __getIter(self):
 ...         if hasattr(self, "Iterator"):
 ...             return self.Iterator
 ...         raise AttributeError, name
 ...     __iter__ = property(__getIter)
 ...
 >>> class Concrete(Base):
 ...     def Iterator(self):
 ...         yield 1
 ...         yield 2
 ...         yield 3
 ...
 >>> iter(Base())
 Traceback (most recent call last):
   File "<stdin>", line 1, in ?
 TypeError: iteration over non-sequence
 >>> iter(Concrete())
 <generator object at 0x02EF152C>
 >>> list(iter(Concrete()))
 [1, 2, 3]

Regards,
Bengt Richter



More information about the Python-list mailing list