代码之家  ›  专栏  ›  技术社区  ›  Jeff.Lu

python:在使用filter()[关闭]生成主列表的代码中,生成器和过滤器是如何工作的?

  •  0
  • Jeff.Lu  · 技术社区  · 6 年前

    注: 这个问题与 using filter and generator to generator endless prime number in python 尽管这两种方法都与Python代码有关,但它们查找的所有素数都达到了给定的限制。

    核心代码实际上非常简单,但我很难理解它是如何工作的。这就是我添加一些调试打印的原因。

    def _odd_number_generator():
        x = 1
        while True:
            x += 2
            print('    _odd_number_generator, x=', x)
            yield x
    
    def _not_divisible(n):
        def func(x):
            print("      filter calling on x:", x, ", n:", n)
            return x % n > 0
        return func
    
    
    def _primes():
        yield 2                                 # return first prime: 2
        odd_numbers = _odd_number_generator()   
        print("  in _primes, #a:  odd_numbers=", odd_numbers)
        while True:
            print("  in _primes, #b:         before next(filter) odd_numbers=", odd_numbers)
    
            # I know this line calling _odd_number_generator and _not_divisible, 
            # but how it works
            n = next(odd_numbers)   
    
            print("  in _primes, #c:         begin yield n:", n)
            yield n
            print("  in _primes, #d: n=", n, ", after yield  odd_numbers=", odd_numbers)
            odd_numbers = filter(_not_divisible(n), odd_numbers)    
            print("  in _primes, #e: n=", n, ", after filter odd_numbers=", odd_numbers)
    
    
    def print_prime_numbes():
        for n in _primes():                                          
            print("  in print_prime_numbes, n = ", n)
            if n < 30:
                print(n)
                print()
                print("print_prime_numbes, begin next loop: n=", n)
            else:
                break
    
    def test_print_prime_numbes():
        print("test_output_triangles() >>>")
        print_prime_numbes()
    

    答案在 用滤波器和生成器在python中生成无穷素数 对于理解链式迭代器非常有帮助。但是,我还是很难理解奇数发生器和 _当处理数字25时,不可除被调用。

    例如,以下是运行时的一个输出:

    print_prime_numbes, begin next loop: n= 23
      in _primes, #d: n= 23 , after yield  odd_numbers= <filter object at 0x000002B0E02366D8>
      in _primes, #e: n= 23 , after filter odd_numbers= <filter object at 0x000002B0E0236F98>
      in _primes, #b:         before next(filter) odd_numbers= <filter object at 0x000002B0E0236F98>
        _odd_number_generator, x= 25
          filter calling on x: 25 , n: 3
          filter calling on x: 25 , n: 5
        _odd_number_generator, x= 27
          filter calling on x: 27 , n: 3
        _odd_number_generator, x= 29
          filter calling on x: 29 , n: 3
          filter calling on x: 29 , n: 5
          filter calling on x: 29 , n: 7
          filter calling on x: 29 , n: 11
          filter calling on x: 29 , n: 13
          filter calling on x: 29 , n: 17
          filter calling on x: 29 , n: 19
          filter calling on x: 29 , n: 23
      in _primes, #c:         begin yield n: 29
      in print_prime_numbes, n =  29
    29
    

    在这里,因为25是可除的,所以生成下一个数字27。我想知道是什么让电话产生了27?

    [编辑]

    在生成23之后,进入下一个循环,奇数应该是这样的: filter(_not划分(23),filter(_not划分(19)…filter(_not划分(7),filter(_not划分(5),filter(_not划分(5),filter(_not划分(3),_odd_generator())。

    当运行“yield n”时,将生成下一个数字25并检查可除性,并且_not divisible返回false。这里,看起来“yield”将在奇数生成器()上运行,并检查新数字是否可以除以3、4、5、.23,直到得到素数。但我想详细了解这里的机制。

    1 回复  |  直到 6 年前
        1
  •  1
  •   MisterMiyagi    6 年前

    为了更好地理解,我们可以看看 filter 作为发电机:

    def filter(condition, iterable):
        for value in iterable:      # 1. consume values from `iterable`
            if condition(value):    # 2. test `condition` for `value`
                yield value         # 3. yield any valid `value`
    

    换言之, odd_numbers = filter(_not_divisible(n), odd_numbers) 是发电机( 滤波器 )包装另一台发电机( _odd_number_generator )对于每个质数,一个新的 滤波器 被包装在现有的包装过滤器周围。查看其中一个初始案例,我们有以下设置:

    odd_numbers = filter(_not_divisible(n=7),  # <filter A>
        filter(_not_divisible(n=5),            # <filter B>
            filter(_not_divisible(n=3),        # <filter C>
                _odd_number_generator()        # <odd_numbers @ x=7>
    ))
    

    现在,如果我们打电话 next(odd_numbers) ?

    • <filter A>:1 取A value 通过呼叫 next(<filter B>)
      • <filter B>:1 取A 价值 通过呼叫 下一个(<筛选b>)
        • <filter C>:1 取A 价值 通过呼叫 next(<odd_numbers @ x=7>)
          • <odd_numbers @ x=7> 增量 x+=2 x=9 并得到它
        • <filter C>:2 测验 _not_divisible(n=3)(9) 找到它 无效
        • <filter C>:3 跳过 循环继续
        • <过滤器C&G:;1 取A 价值 通过呼叫 next(<odd_numbers @ x=9>)
          • <odd_numbers @ x=9> 增量 x+=2 x=11 并得到它
        • <过滤器C&G:;2 测验 _not_divisible(n=3)(11) 发现它是有效的
        • <过滤器C&G:;3 收益率11
      • <filter B>:2 测验 _not_divisible(n=5)(11) 发现它是有效的
      • <filter B>:3 收益率11
    • <filter A>:2 测验 _not_divisible(n=7)(11) 发现它是有效的
    • <filter A>:3 收益率11

    重要的是 _not_divisible(n=3) 不让值9通过。相反,循环 <filter C> 获取另一个值 没有 屈服于 <filter B> <filter A> .

    越来越多地 filter(_not_divibible(n), ...) 层被环绕 _odd_number_generator() ,还有一些附加的层执行“跳过” yield 并要求新的 价值 “。中间发电机能消耗的一般原理 几个 屈服前的值保持不变。

    推荐文章