注意:这个问题与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,直到它得到一个素数。但我想详细了解这里的机制。
为了更好地理解,我们也可以将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
”。中间生成器在屈服之前可以消耗多个值的一般原则保持不变。