【问题标题】:Function generators vs class generators in Python 3Python 3 中的函数生成器与类生成器
【发布时间】:2016-12-16 18:19:28
【问题描述】:

为什么函数生成器和类生成器的行为不同?我的意思是,对于类生成器,我可以根据需要多次使用生成器,但是对于函数生成器,我只能使用一次吗?为什么会这样?

def f_counter(low,high):
    counter=low
    while counter<=high:
        yield counter
        counter+=1

class CCounter(object):
    def __init__(self, low, high):
        self.low = low
        self.high = high
    def __iter__(self):
       counter = self.low
       while self.high >= counter:
            yield counter
            counter += 1

f_gen=f_counter(5,10)
for i in f_gen:
    print(i,end=' ')

print('\n')

for j in f_gen:
    print(j,end=' ')  #no output

print('\n')

c_gen=CCounter(5,10)
for i in c_gen:
    print(i,end=' ') 

print('\n')

for j in c_gen:
    print(j,end=' ')

【问题讨论】:

    标签: python python-3.x generator


    【解决方案1】:

    调用f_gen() 函数会生成iterator(具体来说,是generator iterator)。迭代器只能循环一次。你的类不是一个迭代器,而是一个iterable,一个可以产生任意数量的迭代器的对象。

    您的类每次使用for 时都会生成一个 生成器迭代器,因为foriter() function 应用于您传入的对象,而后者又调用object.__iter__(),它在您的实现中,每次调用它都会返回一个 new 生成器迭代器。

    换句话说,您可以通过在循环之前调用iter(instance)instance.__iter__() 使类的行为方式相同:

    c_gen = CCounter(5,10)
    c_gen_iterator = iter(c_gen)
    for i in c_gen_iterator:
        # ...
    

    您还可以通过从__iter__ 返回self 并添加object.__next__() method(Python 2 中的object.next())将CCounter() 变成一个迭代器

    class CCounter(object):
        def __init__(self, low, high):
            self.low = low
            self.high = high
        def __iter__(self):
           return self
        def __next__(self):
           result = self.low
           if result >= self.high:
               raise StopIteration()
           self.low += 1
           return result
    

    【讨论】:

      【解决方案2】:

      您的类是可迭代的,但本身不是迭代器。每次调用 iter 时,都会得到一个新的迭代器。

      如果你想用一个类来复制生成器函数的行为,那么你需要一个像这样的迭代器:

      class CCounter(object):
          def __init__(self, low, high):
              self.low = low
              self.high = high
              self.counter = self.low
          def __iter__(self):
             return self
          def __next__(self):
             if self.counter > self.high:
                 raise StopIteration()
             val = self.counter
             self.counter += 1
             return val
      

      【讨论】:

        猜你喜欢
        • 2011-04-17
        • 2011-08-07
        • 1970-01-01
        • 2013-10-02
        • 2013-03-20
        • 2012-10-25
        • 1970-01-01
        相关资源
        最近更新 更多