我有这段代码:
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__
将不再是同一个对象(即类对象)。也许关于有界函数的整个事情应该是语法糖而不是在运行时。但是,另一方面,语法糖不应该真正依赖于内容。我想在某个地方必须进行一些权衡。
答案 0 :(得分: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对象模型的许多细微之处,并且没有理由去那条路。
答案 1 :(得分:2)
在我看来,最好的解决方案是@Sven one,毫无疑问。那就是说,你想要做的事情看起来非常黑暗 - 我的意思是,将__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__()
中实例化它: / p>
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解决方案看起来更精细。我刚刚回答了尝试解释为什么你的代码没有按照你的预期行事,并提供一些关于做你想做的事情的信息 - 尽管如此,这可能是有用的。