我想使用一些生成器表达式作为一些昂贵的数据计算的属性。如果可能的话,我希望能够做到这样的事情:
class Test:
def __init__(self):
self.data = []
self.evens = (i for i in self.data if i % 2 == 0)
def __main__():
t = Test()
t.data = [1,2,3,4,5,6,7,8]
for item in t.evens:
print(item)
if __name__ == '__main__':
__main__()
我希望看到这个打印出2 4 6 8
,但这没有输出。我在这里犯了一些简单的错误吗?
我在这里尝试做的是否可行,或者我需要使用yield
来做这件事吗?
答案 0 :(得分:6)
虽然其他答案已正确诊断错误(您的evens
生成器正在使用原始的空data
列表进行初始化),但我认为建议为data
设置值仍然不会做你想做的事。
目前,您只能迭代evens
一次,之后就会消耗掉它。我认为你想要的是evens
始终可以作为当前data
值所具有的偶数值的生成器来访问。这样做的方法是使它成为property
,其函数在每次调用时返回生成器:
class Test:
def __init__(self):
self.data = []
@property
def evens(self):
return (i for i in self.data if i % 2 == 0)
用法:
>>> t = Test()
>>> t.data = [1, 2, 3, 4, 5, 6]
>>> list(t.evens)
[2, 4, 6]
>>> list(t.evens) # works more than once
[2, 4, 5]
>>> t.data = [10, 15, 20, 25, 30]
>>> list(t.evens)
[10, 20, 30]
如果你需要一个更复杂的生成器,你可以在函数中使用yield
,而不是返回一个生成器对象,但生成器表达式可以很容易地获得偶数值。
答案 1 :(得分:2)
只有在初始化类的实例时才会调用生成器表达式self.evens = (i for i in self.data if i % 2 == 0)
。它使用self.data
初始化为空列表,因此包含该列表中所有偶数的生成器表达式为空。再次设置data
时,不会再次调用生成器表达式行。
将代码更改为:
class Test:
def __init__(self, data):
self.data = data
self.evens = (i for i in self.data if i % 2 == 0)
def main():
t = Test([1,2,3,4,5,6,7,8])
for item in t.evens:
print(item)
if __name__ == '__main__':
main()
应该具有你期望的效果。
答案 2 :(得分:2)
生成器推迟创建其值,但它使用创建生成器时存在的self.data
值。通过稍后使用名称 self.data
,它不会像您期望的那样推迟该部分。
这很容易证明:
>>> dat = range(10,20)
>>> evens = (i for i in dat if i % 2 == 0)
>>> dat = range(10)
>>> list(evens)
[10, 12, 14, 16, 18]
>>> evens = (i for i in dat if i % 2 == 0)
>>> list(evens)
[0, 2, 4, 6, 8]
每当data
发生更改时,您都需要重新创建生成器,并且最初将data
作为__init__
方法的参数可能是有意义的。
答案 3 :(得分:1)
你没有把数据传入课堂!
创建类时调用__init__
,创建类时self.data
为空列表,因此当您尝试:[i for i in self.data if i % 2 == 0]
迭代空列表时! / p>
试试这个:
class Test:
def __init__(self,data):
self.data = data
self.evens = [i for i in self.data if i % 2 == 0]
def __main__():
x = [1,2,3,4,5,6,7,8]
t = Test(x)
for item in t.evens:
print(item)
if __name__ == '__main__':
__main__()
答案 4 :(得分:1)
您的生成器表达式初始化为空data
。将data
传递给__init__
方法:
class Test:
def __init__(self, data):
self.evens = (i for i in data if i % 2 == 0)
def __main__():
t = Test(data=[1,2,3,4,5,6,7,8])
for item in t.evens:
print(item)
if __name__ == '__main__':
__main__()
打印:
2
4
6
8