1

私はこのコードを持っています:

class LFSeq: # lazy infinite sequence with new elements from func
    def __init__(self, func):
        self.evaluated = []
        self.func = func
    class __iter__:
        def __init__(self, seq):
            self.index = 0
            self.seq = seq
        def next(self):
            if self.index >= len(self.seq.evaluated):
                self.seq.evaluated += [self.seq.func()]
            self.index += 1
            return self.seq.evaluated[self.index - 1]

そして、他のユーザー定義関数と同じようLFSeq.__iter__に、インスタンスにバインドされるようになることを明示的に望んでいます。LFSeq

ただし、クラスではなくユーザー定義関数のみがバインドされているため、この方法では機能しません。

のような関数デコレータを紹介すると

def bound(f):
    def dummy(*args, **kwargs):
        return f(*args, **kwargs)
    return dummy

それから私はそれで飾ることができ__iter__、それは機能します:

...
@bound
class __iter__:
    ...

しかし、これはどういうわけかハッキーで一貫性がないように感じます。他に方法はありますか?そうすべきですか?

そうでなければ、もはや同じオブジェクト(つまりクラスオブジェクト)ではなくなるので、私はそうだと思いLFSeq.__iter__ますLFSeq(None).__iter__。たぶん、有界関数についてのすべては、実行時にそれを持っているのではなく、構文糖衣であるべきでした。しかし、反対に、構文糖衣は実際にはコンテンツに依存するべきではありません。どこかでトレードオフが必要だと思います。

4

2 に答える 2

3

あなたがやろうとしていることに対する最も簡単な解決策は、__iter__()メソッドをジェネレータ関数として定義することです:

class LFSeq(object):
    def __init__(self, func):
        self.evaluated = []
        self.func = func
    def __iter__(self):
        index = 0
        while True:
            if index == len(self.evaluated):
                self.evaluated.append(self.func())
            yield self.evaluated[index]
            index += 1

あなたのアプローチでは、Python オブジェクト モデルの多くの機微に対処する必要があり、その方法を取る理由はありません。

于 2012-06-14T16:04:10.643 に答える
2

私の意見では、最良の解決策は@Svenのものであり、間違いありません。そうは言っても、あなたがやろうとしていることは本当に非常にハックに思えます-つまり__iter__、クラスとして定義することです。別のクラス内でクラスを宣言することは、メソッドを定義することとは異なり、属性を定義することに似ているため、機能しません。コード

class LFSeq:
    class __iter__:

クラス フィールドを作成する属性とほぼ同じです。

class LFSeq:
     __iter__ = type('__iter__', (), ...)

次に、クラス内で属性を定義するたびに、これは特定のインスタンスではなく、クラス自体にバインドされます。

LFSeq@Sven ソリューションに従うべきだと思いますが、他の理由で本当にクラスを定義したい場合は、ジェネレーター クラスがインスタンス自体から何にも依存しないため、幸運なようです。外部でイテレータ クラスを定義するだけです。

class Iterator(object):
    def __init__(self, seq):
        self.index = 0
        self.seq = seq
    def next(self):
        if self.index >= len(self.seq.evaluated):
            self.seq.evaluated += [self.seq.func()]
        self.index += 1
        return self.seq.evaluated[self.index - 1]

LFSeq.__iter__()メソッド内でインスタンス化します。

class LFSeq(object): # lazy infinite sequence with new elements from func
    def __init__(self, func):
        self.evaluated = []
        self.func = func
    def __iter__(self):
        return Iterator(self)

最終的にイテレータ クラスをインスタンスにバインドする必要がある場合は、 内でイテレータ クラスを定義し、それを属性LFSeq.__init__()に配置して、でインスタンス化できます。selfLFSeq.__iter__()

class LFSeq(object): # lazy infinite sequence with new elements from func
    def __init__(self, func):

        lfseq_self = self # For using inside the iterator class

        class Iterator(object): # Iterator class defined inside __init__
            def __init__(self):
                self.index = 0
                self.seq = lfseq_self # using the outside self
            def next(self):
                if self.index >= len(self.seq.evaluated):
                    self.seq.evaluated += [self.seq.func()]
                self.index += 1
                return self.seq.evaluated[self.index - 1]

        self.iterator_class = Iterator # setting the itrator
        self.evaluated = []
        self.func = func

    def __iter__(self):
        return self.iterator_class() # Creating an iterator

ただし、私が言ったように、@Sven ソリューションの方が優れているようです。コードが期待どおりに動作しなかった理由を説明し、やりたいことを実行するための情報を提供してくださいと答えましたが、それでも役立つ場合があります。

于 2012-06-14T16:24:45.703 に答える