Python: how does the generator and filter work in the codes generating prime list with filter() [closed]

谁说胖子不能爱 提交于 2019-12-08 05:13:25

问题


Note: This question is different with using filter and generator to generator endless prime number in python although both of them are related to Python code finding all the prime numbers up to a given limit.

The core codes are actually very simple, but it's hard for me to understand how it works. That's the reason I add some debug prints.

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()

The answer in using filter and generator to generator endless prime number in python is very helpful to understand the chained iterator. But still, I get problem to understand how the _odd_number_generator and _not_divisible is being called when handling the number 25.

For example, here is a piece of outputs when running:

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

Here, because 25 is divisible, next number, 27, is being generated. I want to know what makes the calling to generate 27?

[Edited]

After yield 23, and go to next loop, the odd_numbers should be something like this: 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())).

When running "yield n", the next number 25, is being generated and check the divisibility, and _not_divisible return False. Here, looks like the 'yield' will run next on _odd_generator() and check if the new number can be divided by 3,4,5,..23 until it gets a prime. But I want to know the mechanism here in details.


回答1:


For better understanding, we can look at filter as a generator as well:

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`

In other words, odd_numbers = filter(_not_divisible(n), odd_numbers) is a generator (filter) wrapping another generator (_odd_number_generator). For every prime number, a new filter is wrapped around the existing wrapped filters. Looking at one of the initial cases, we have this setup:

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>
))

Now, what happens if we call next(odd_numbers)?

  • <filter A>:1 fetches a value by calling next(<filter B>)
    • <filter B>:1 fetches a value by calling next(<filter C>)
      • <filter C>:1 fetches a value by calling next(<odd_numbers @ x=7>)
        • <odd_numbers @ x=7> increments x+=2 to x=9 and yields it
      • <filter C>:2 tests _not_divisible(n=3)(9) and finds it invalid
      • <filter C>:3 is skipped and the loop continues
      • <filter C>:1 fetches a value by calling next(<odd_numbers @ x=9>)
        • <odd_numbers @ x=9> increments x+=2 to x=11 and yields it
      • <filter C>:2 tests _not_divisible(n=3)(11) and finds it valid
      • <filter C>:3 yields 11
    • <filter B>:2 tests _not_divisible(n=5)(11) and finds it valid
    • <filter B>:3 yields 11
  • <filter A>:2 tests _not_divisible(n=7)(11) and finds it valid
  • <filter A>:3 yields 11

The important part is that _not_divisible(n=3) does not let the value 9 pass. Instead, the loop in <filter C> fetches another value without yielding to <filter B> and <filter A>.

As more and more filter(_not_divibible(n), ...) layers are wrapped around _odd_number_generator(), there are additional layers which do the "skip yield and request new value". The general principle, that an intermediate generator can consume several values before yielding, remains the same.



来源:https://stackoverflow.com/questions/54386716/python-how-does-the-generator-and-filter-work-in-the-codes-generating-prime-lis

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!