0

I'm wondering if it's possible to make a class object iterable in Python (ie. a subclass of type, NOT an instance of a class).

I've tried the following code:

class Foo:
    @classmethod
    def __iter__(cls):
        yield 1


print(next(Foo.__iter__()))  # prints 1
print(next(iter(Foo)))  # TypeError: 'type' object is not iterable
Agost Biro
  • 2,709
  • 1
  • 20
  • 33
  • Does this answer your question? [Build a Basic Python Iterator](https://stackoverflow.com/questions/19151/build-a-basic-python-iterator) – Panagiotis Simakis May 24 '20 at 07:34
  • 1
    No, that answer is about making a class instance iterable, I'm asking about a class object (a subclass of `type`) – Agost Biro May 24 '20 at 07:35
  • 2
    Most class objects are not subclasses of `type`. All class objects are *instances* of `type`. – user2357112 May 24 '20 at 07:43
  • thanks @Tomerikoo that indeed answers the question. It didn't turn up in search unfortunately. – Agost Biro May 24 '20 at 07:47
  • It is certainly possible because a class is nothing more than an instance of its metaclass (`type` for ordinary ones, but you can customize it). Simply I cannot imagine a real world use case... – Serge Ballesta May 24 '20 at 07:47

2 Answers2

1

Turns out it's possible with metaclasses.

class Foo(type):
    def __iter__(self):
        yield self.baz


class Bar(metaclass=Foo):
    baz = 1


print(type(Bar))  # prints "<class '__main__.Foo'>"
print(next(Bar.__iter__()))  # prints "1"
print(next(iter(Bar)))  # prints "1"

Thanks @DanielB for pointing me in the right direction.

Agost Biro
  • 2,709
  • 1
  • 20
  • 33
0

This isn't possible, as it would imply that all type objects are iterable - as you stated, classes are of type type. The underlying reason for this is that the __iter__ method is looked up on the type, not the value. E.g., in:

for i in Foo:
    print(i)

Python will look up type(Foo).__iter__, not Foo.__iter__.

DanielB
  • 2,798
  • 1
  • 19
  • 29