Python:生成器和过滤器如何在代码生成素数列表中使用filter()[关闭]

问题描述 投票:1回答:1

注意:这个问题与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()

using filter and generator to generator endless prime number in python中的答案对于理解链式迭代器非常有帮助。但是,我仍然有问题要理解在处理数字25时如何调用_odd_number_generator和_not_divisible。

例如,运行时这是一段输出:

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?

将帖子

在yield 23之后,转到下一个循环,odd_numbers应该是这样的:filter(_not_divisible(23),filter(_not_divisible(19)... filter(_not_divisible(7),filter(_not_divisible(5),filter( _not_divisible(5),filter(_not_divisible(3),_odd_generator()))。

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

python generator primes iterable-unpacking
1个回答
2
投票

为了更好地理解,我们也可以将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)是包裹另一个发电机(filter)的发电机(_odd_number_generator)。对于每个素数,新的filter包裹在现有的包装过滤器周围。看一下最初的案例,我们有这样的设置:

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通过调用value获取next(<filter B>) <filter B>:1通过调用value获取next(<filter C>) <filter C>:1通过调用value获取next(<odd_numbers @ x=7>) <odd_numbers @ x=7>x+=2增加到x=9并获得它 <filter C>:2测试_not_divisible(n=3)(9)并发现它无效 跳过<filter C>:3并继续循环 <filter C>:1通过调用value获取next(<odd_numbers @ x=9>) <odd_numbers @ x=9>x+=2增加到x=11并获得它 <filter C>:2测试_not_divisible(n=3)(11)并发现它有效 <filter C>: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并请求新的value”。中间生成器在屈服之前可以消耗多个值的一般原则保持不变。

© www.soinside.com 2019 - 2024. All rights reserved.