考虑以下虚拟示例:
def common_divisors_generator(n, m):
# Init code
factors_n = [i for i in range(1, n + 1) if n%i == 0]
factors_m = [i for i in range(1, m + 1) if m%i == 0]
# Iterative code
for fn in factors_n:
for fm in factors_m:
if fn == fm:
yield fn
# The next line is fast because no code is executed yet
cdg = common_divisors_generator(1537745, 373625435)
# Next line is slow because init code is executed on first iteration call
for g in cdg:
print(g)
一旦生成器第一次被迭代(与生成器初始化时相反),就会执行花费很长时间来计算的初始化代码。我希望在生成器初始化时执行它的init代码。
为此,我将生成器转换为迭代器类,如下所示:
class CommonDivisorsIterator(object):
def __init__(self, n, m):
# Init code
self.factors_n = [i for i in range(1, n + 1) if n%i == 0]
self.factors_m = [i for i in range(1, m + 1) if m%i == 0]
def __iter__(self):
return self
def __next__(self):
# Some Pythonic implementation of the iterative code above
# ...
return next_common_divisor
与生成器中带有__next__
关键字的迭代代码的简单性相比,我能想到的实现上述yield
方法的所有方式都非常麻烦。
在迭代器类中实现__next__
方法的最Python方式是什么?
或者,如何修改生成器,以便在初始化时执行初始化代码?
答案 0 :(得分:4)
在两种情况下(无论使用函数还是类),解决方案都是将实现分为两个函数:设置函数和生成器函数。
在函数中使用yield
会将其转换为生成器函数,这意味着它在被调用时会返回生成器。但是,即使不使用yield
,也无法阻止您创建生成器并返回它,就像这样:
def common_divisors_generator(n, m):
factors_n = [i for i in range(1, n + 1) if n%i == 0]
factors_m = [i for i in range(1, m + 1) if m%i == 0]
def gen():
for fn in factors_n:
for fm in factors_m:
if fn == fm:
yield fn
return gen()
如果您使用的是类,则无需实现__next__
方法。您可以在yield
方法中使用__iter__
:
class CommonDivisorsIterator(object):
def __init__(self, n, m):
self.factors_n = [i for i in range(1, n + 1) if n%i == 0]
self.factors_m = [i for i in range(1, m + 1) if m%i == 0]
def __iter__(self):
for fn in self.factors_n:
for fm in self.factors_m:
if fn == fm:
yield fn