是否可以并且建议子类化生成器函数?

cam*_*mil 3 python generator python-2.7

我经常使用返回某个类的生成器.我想做的是将生成器类子类化,以便我可以使用适合于生成该类实例的生成器的方法.例如,我想做的一件事就是有一个方法返回一个过滤基础生成器的生成器.

我想做这样的事情:

class Clothes(object):
    def __init__(self, generator):
        self.generator = generator

    def get_red(self):
        return (c for c in self.generator if c.color=="red")

    def get_hats(self):
        return (c for c in self.generator if c.headgear)
Run Code Online (Sandbox Code Playgroud)

我想把衣服当作衣服的集合.我没有对集合进行子类化的原因是我很少想要按原样使用整个服装集合,通常只需要进一步过滤它.但是,我经常需要各种过滤的衣服系列.如果可能的话,我希望Clothes本身就是一个生成器,因为我打算使用它,但是在尝试子类时我遇到了错误types.GeneratorType.

ch3*_*3ka 7

types.GeneratorType 
Run Code Online (Sandbox Code Playgroud)

定义为:

def _g():
    yield 1
GeneratorType = type(_g())
Run Code Online (Sandbox Code Playgroud)

如你所见,它不是常规的class.

现在,是什么让发电机变得特别?不多.要利用它generator protocol,所有人必须做的就是实现iterator protocol.有一个很好的捷径:next()当你__iter__是一个发电机时,你可以获得免费的.而这正是如何collections.Iterable定义的:

class Iterable(metaclass=ABCMeta):

    @abstractmethod
    def __iter__(self):
        while False:
            yield None

    @classmethod
    def __subclasshook__(cls, C):
        if cls is Iterable:
            if any("__iter__" in B.__dict__ for B in C.__mro__):
                return True
        return NotImplemented
Run Code Online (Sandbox Code Playgroud)

所以,只需用它来构建你的发电机.


geo*_*org 5

正如您在前面的问题的评论中所指出的,返回生成器表达式通常是个坏主意.引用PEP 289:

...强烈建议用户在立即使用其参数的函数内使用生成器表达式.对于更复杂的应用程序,完整的生成器定义总是优于范围,生命周期和绑定方面.

本着上述精神,我建议:

  • 通过定义__iter__(反过来,可以是生成器)使主类可迭代.
  • 定义get_xxx为迭代的生成器selfyield来自它的特定值

例:

class Numbers(object):

    def __iter__(self):
        for x in range(10):
            yield x

    def get_odd(self):
        for x in self:
            if x & 1:
                yield x


nums = Numbers()

for x in nums:
    print x   # 0 1 2 3...

for x in nums.get_odd():
    print x # 1 3 5...
Run Code Online (Sandbox Code Playgroud)