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__:
    ...

然而,这感觉有点hacky和不一致。还有其他方法吗?应该是这样吗?

我猜是的,否则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__', (), ...)

然后,每次在类中定义一个属性时,它都绑定到类本身,而不是特定实例。

我认为您应该遵循@Sven 解决方案,但是如果您真的想出于任何其他原因定义一个类,那么您似乎很幸运,因为您的生成器类不依赖于LFSeq实例本身的任何内容。只需在外面定义迭代器类:

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__(),把它放在一个self属性上,然后在里面实例化它LFSeq.__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 回答