4

特定のクラスを返すジェネレーターをよく使用します。私がやりたいのは、ジェネレーター クラスをサブクラス化して、そのクラスのインスタンスを生成するジェネレーターに適したメソッドを使用できるようにすることです。たとえば、私がやりたいことの 1 つは、ベース ジェネレーターをフィルター処理するジェネレーターを返すメソッドを持つことです。

私はこのようなことをしたい:

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)

服のコレクションとして扱いたい服教室。コレクションをサブクラス化しない理由は、服のコレクション全体をそのまま使用することはめったになく、通常はさらにフィルタリングする必要があるためです。ただし、さまざまなフィルター処理された服のコレクションが必要になることがよくあります。できれば、Clothes 自体をジェネレーターにしたいので、そのように使用したいのですが、サブクラス化しようとするとエラーが発生しますtypes.GeneratorType

4

3 に答える 3

7
types.GeneratorType 

と定義されている:

def _g():
    yield 1
GeneratorType = type(_g())

ご覧のとおり、通常の ではありません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

したがって、それを使用してジェネレータを構築してください。

于 2012-04-28T10:55:48.147 に答える
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...
于 2012-04-28T10:49:18.463 に答える
4

ジェネレーターはイテレーターのように振る舞うものですが、それが表すシーケンスは、タプルやリストとは異なり、反復ステップごとに遅延して生成されます。ジェネレーターを作成する一般的な方法は、ジェネレーター式を使用するか、yieldステートメントを使用することです。他のメカニズムが存在する場合は黒魔術であり、近づかないようにしてください。

したがって、それを忘れてtypes.GeneratorType継承する必要があります。通常は、ジェネレーターをまとめてラップまたはチェーンします。サンプルコードにあるように、ジェネレータ式でそれを行うことができます。または、素晴らしいitertools標準モジュールを使用することもできます。

于 2012-04-28T09:40:08.680 に答える