Python 为什么这个FizzBuzz生成器要比这个FizzBuzz迭代器类快很多?

Python 为什么这个FizzBuzz生成器要比这个FizzBuzz迭代器类快很多?,python,performance,iterator,generator,fizzbuzz,Python,Performance,Iterator,Generator,Fizzbuzz,在学习了迭代器类方法和生成器之后,我使用每种习惯用法测试了简单的Fizz Buzz解决方案的性能特征: >>> from timeit import timeit >>> timeit('tuple(fizzbuzz.FizzBuzzIterator(10))', 'import fizzbuzz') 13.281935930252075 >>> timeit('tuple(fizzbuzz.fizz_buzz_generator(10))'

在学习了迭代器类方法和生成器之后,我使用每种习惯用法测试了简单的Fizz Buzz解决方案的性能特征:

>>> from timeit import timeit
>>> timeit('tuple(fizzbuzz.FizzBuzzIterator(10))', 'import fizzbuzz')
13.281935930252075
>>> timeit('tuple(fizzbuzz.fizz_buzz_generator(10))', 'import fizzbuzz')
7.619534015655518
根据
timeit
,生成器函数大约比迭代器类快1¾倍

我的问题是:为什么这个FizzBuzz生成器要比这个FizzBuzz迭代器类快很多

FizzBuzz迭代器类 嘶嘶声发生器功能
def嘶嘶声发生器(低、高=无):
如果“高”为“无”:
高=低
cur=1
其他:
电流=最大值(低,1)

而cur显然,生成器的实现效率高于迭代器

您的第一个解决方案具有以下有趣的特征:

  • 它使用对象
  • 对于n个数上的迭代,调用3+n方法并访问2+4.n属性,这两种操作都可能很慢
  • 异常用于控制流
  • 第二个解决方案不执行这些操作,而是
    产生
    s,这意味着语言运行库执行繁重的工作。由于运行时通常是用C实现的,因此这比第一个解决方案的高级代码优化得多

    下一步,你应该考虑你真正的标杆管理。对于一个好的基准测试,您应该选择不同的输入大小n,并观察这两个解决方案在不同尺度下的比较

    • 对于非常小的n,我们预计初始成本占主导地位。这与您的结果一致,因为执行函数调用比创建对象花费更少
    • 对于较大的n,我们期望算法的特性占主导地位。由于算法完全相同,因此图形应该具有相同的形状。但每次迭代,第一个解决方案的成本要高得多(四个属性访问,一个方法调用)。然后,这两种解决方案将是斜率略有不同的图。每次迭代成本的精确关系只能通过获得大量输入大小n的大量计时数据集,然后对该数据拟合函数来评估

    我绘制了一些图表,以查看绘制的线条有多大差异。这种可衡量的差异令人惊讶。再次感谢你的回答!感谢版主/管理员删除了离题答案:)
    class FizzBuzzIterator:
    
        def __init__(self, low, high=None):
            if high is None:
                self.high = low
                self.current = 1
            else:
                self.high = high
                self.current = max(low, 1)
    
        def __iter__(self):
            return self
    
        def next(self):
            if self.current > self.high:
                raise StopIteration
            else:
                c = self.current
                self.current += 1
                if (c % 5 + c % 3) == 0:
                    return 'FizzBuzz'
                elif c % 5 == 0:
                    return 'Buzz'
                elif c % 3 == 0:
                    return 'Fizz'
                else:
                    return str(c)
    
    def fizz_buzz_generator(low, high=None):
        if high is None:
            high = low
            cur = 1
        else:
            cur = max(low, 1)
        while cur <= high:
            c = cur
            cur += 1
            if (c % 5 + c % 3) == 0:
                yield 'FizzBuzz'
            elif c % 5 == 0:
                yield 'Buzz'
            elif c % 3 == 0:
                yield 'Fizz'
            else:
                yield str(c)