迭代类型而不实例化它

Eme*_*kin 5 python static-methods iterator class magic-methods

问题

我希望能够迭代类型而不实例化它,类似于枚举。

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
Run Code Online (Sandbox Code Playgroud)

这种行为对于枚举来说是可能的,但前提是ALLOWED_VALUES有效的 python 名称。我希望在没有此限制的情况下具有相同的迭代行为。

我尝试过的

我尝试将其实现__iter__()staticmethodon ,这样就不需要使用Foo的实例来获取它。这允许我迭代,但会引发错误。这似乎是因为在 上查找方法,而不是在(因为是一个对象)上查找方法。FooIteratorFoo.__iter__()iter(Foo)iter(Foo)__iter__typeFooFootype

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)
Run Code Online (Sandbox Code Playgroud)

che*_*ner 5

Enum是可迭代的,因为它使用不同的元类(EnumMeta而不是type)来创建它。__iter__您可以定义自己的元类来提供其本身所缺乏的定义type

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
Run Code Online (Sandbox Code Playgroud)