pythonsyntaxattributesstatic-methodsloops

Python: Make class iterable


I have inherited a project with many large classes constituent of nothing but class objects (integers, strings, etc). I'd like to be able to check if an attribute is present without needed to define a list of attributes manually.

Is it possible to make a python class iterable itself using the standard syntax? That is, I'd like to be able to iterate over all of a class's attributes using for attr in Foo: (or even if attr in Foo) without needing to create an instance of the class first. I think I can do this by defining __iter__, but so far I haven't quite managed what I'm looking for.

I've achieved some of what I want by adding an __iter__ method like so:

class Foo:
    bar = "bar"
    baz = 1
    @staticmethod
    def __iter__():
        return iter([attr for attr in dir(Foo) if attr[:2] != "__"])

However, this does not quite accomplish what I'm looking for:

>>> for x in Foo:
...     print(x)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'classobj' object is not iterable

Even so, this works:

>>> for x in Foo.__iter__():
...     print(x)
bar
baz

Solution

  • Add the __iter__ to the metaclass instead of the class itself (assuming Python 2.x):

    class Foo(object):
        bar = "bar"
        baz = 1
        class __metaclass__(type):
            def __iter__(self):
                for attr in dir(self):
                    if not attr.startswith("__"):
                        yield attr
    

    For Python 3.x, use

    class MetaFoo(type):
        def __iter__(self):
            for attr in dir(self):
                if not attr.startswith("__"):
                    yield attr
    
    class Foo(metaclass=MetaFoo):
        bar = "bar"
        baz = 1