将Generator转换为Iterator类的最佳方法

Dan*_*aga 6 python iterator generator

考虑下面的虚拟示例:

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)
Run Code Online (Sandbox Code Playgroud)

一旦生成器第一次被迭代(与生成器初始化时相反),就会执行花费很长时间来计算的初始化代码。我希望在生成器初始化时执行它的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
Run Code Online (Sandbox Code Playgroud)

__next__与生成器中带有yield关键字的迭代代码的简单性相比,我能想到的实现上述方法的所有方式都非常麻烦。

__next__在迭代器类中实现该方法的最Pythonic方式是什么?

或者,如何修改生成器,以便在初始化时执行初始化代码?

Ara*_*Fey 5

在两种情况下(无论使用函数还是类),解决方案都是将实现分为两个函数:设置函数和生成器函数。

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()
Run Code Online (Sandbox Code Playgroud)

而且,如果您使用的是类,则无需实现__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
Run Code Online (Sandbox Code Playgroud)