I want to be able to iterate over a type without instantiating it, similar to an enum.
class Foo:
"""Class I want to iterate over without instantiating."""
ALLOWED_VALUES = (1, 2, 3)
# I want iterating over `Foo` to be equivalent to iterating over `Foo.ALLOWED_VALUES`
for val_from_tuple, val_from_foo in zip(Foo.ALLOWED_VALUES, Foo):
assert val_from_tuple == val_from_foo
This behaviour is possible with an enum, but only if ALLOWED_VALUES
are valid python names. I want to have the same iteration behaviour without this restriction.
I tried implementing __iter__()
as a staticmethod
on Foo
so that an instance of Foo
wouldn't be needed to get an Iterator
for it. This allows me to iterate over Foo.__iter__()
, but iter(Foo)
raises an error. This seems to be because iter(Foo)
looks for an __iter__
method on type
, not on Foo
(since Foo
is a type
object).
class Foo:
"""Class I want to iterate over without instantiating."""
ALLOWED_VALUES = (1, 2, 3)
@staticmethod
def __iter__():
return Foo.ALLOWED_VALUES
# This works, but isn't what I want because it involves calling `__iter__()` explicitly.
for val in Foo.__iter__():
print(val)
# This raises an error:
# `TypeError: 'type' object is not iterable`
for val in Foo:
print(val)
Enum
is iterable because it uses a different metaclass (EnumMeta
rather than type
) to create it. You can define your own metaclass to provide a definition of __iter__
which type
itself lacks.
class IterableClass(type):
def __iter__(self):
yield from self.ALLOWED_VALUES
class Foo(metaclass=IterableClass):
ALLOWED_VALUES = (1,2,3)
for x, y in zip(Foo.ALLOWED_VALUES, Foo):
assert x == y