4

I would like to define a single object that can be iterated over without having to create a class and then an instance. Something like this:

class Thing(object):
    stuff = ["foo", "bar", "baz"]

    @classmethod
    def __iter__(cls):
        return iter(cls.stuff)

for thing in Thing:
    print thing

However this doesn't actually work. Is there any way to do this?

DanielGibbs
  • 9,910
  • 11
  • 76
  • 121
  • 4
    For a class define `__iter__` on the metaclass. – Ashwini Chaudhary Apr 20 '15 at 22:06
  • Magic method lookup occurs on the class. So you'll either have to create an instance and class or class and metaclass. But it also seems like you could just subclass list (at least in your example). – jedwards Apr 20 '15 at 22:12
  • @jedwards Ok, I was trying to avoid creating extra things in the namespace of my module but I guess I'll just have to deal with it. This is a much simplified example, in my actual use case there's more internal state than just a list. – DanielGibbs Apr 20 '15 at 22:16

2 Answers2

3

What Ashwini correctly suggested in his comment is the following. This works in Python 2.

class ThingType(type):
    __stuff__ = ["foo", "bar", "baz"]

    @classmethod
    def __iter__(cls):
        return iter(cls.__stuff__)

class Thing(object):
    __metaclass__ = ThingType

for thing in Thing:
    print thing

And this works in Python 3:

class ThingType(type):
    __stuff__ = ["foo", "bar", "baz"]

    @classmethod
    def __iter__(cls):
        return iter(cls.__stuff__)

class Thing(object, metaclass=ThingType):
    pass

for thing in Thing:
    print(thing)
nickie
  • 5,608
  • 2
  • 23
  • 37
0

Does Thing actually need to be a type? You could make it an object that has type-like callable behavior, which would probably be simpler:

class RealThing(object):
  pass

class ThingFactory(object):
  def __iter__(self):
    return iter(["foo", "bar", "baz"])

  def __call__(self):
    return RealThing()

Thing = ThingFactory()
Daniel Pryden
  • 59,486
  • 16
  • 97
  • 135