迭代一个类型而不实例化它

5

问题

我希望能够像枚举一样在不实例化类型的情况下迭代它。

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

这种行为可以使用枚举实现,但只有在ALLOWED_VALUES是有效的Python名称时才能实现。我希望在没有这个限制的情况下具有相同的迭代行为。

我尝试过的方法

我尝试将__iter__()实现为Foo上的一个staticmethod,这样就不需要一个Foo实例来获取其迭代器。这使我能够遍历Foo.__iter__(),但iter(Foo)会引发错误。这似乎是因为iter(Foo)在type上查找__iter__方法,而不是在Foo上查找__iter__方法(因为Foo是一个type对象)。
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)
1个回答

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

一个小问题:在元类方法中,考虑将self参数命名为cls,以提醒读者它正在处理一个类对象。 - user4815162342
我对此持有不同的观点。在元类中仍然可以定义类方法,所以我通常认为更好的做法是简单地记住元类的实例就是一个类。 - chepner
1
(虽然可以使用“cls”/“metacls”代替“self”/“cls”。) - chepner

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接