问题
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 avalue
by callingnext(<filter B>)
<filter B>:1
fetches avalue
by callingnext(<filter C>)
<filter C>:1
fetches avalue
by callingnext(<odd_numbers @ x=7>)
<odd_numbers @ x=7>
incrementsx+=2
tox=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 avalue
by callingnext(<odd_numbers @ x=9>)
<odd_numbers @ x=9>
incrementsx+=2
tox=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