Python: generator和filter在filter()生成prime list的代码中是如何工作的
Python: how does the generator and filter work in the codes generating prime list with filter()
注意:
这个问题与 不同,尽管它们都与 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()
中的答案对理解链式迭代器很有帮助。但是,我仍然无法理解 _odd_number_generator 和
_not_divisible 正在处理号码 25 时被调用。
比如下面是运行ning时的一段输出:
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 应该是这样的:
过滤器(_not_divisible(23),过滤器(_not_divisible(19)...过滤器(_not_divisible(7),过滤器(_not_divisible(5),过滤器(_not_divisible(5),过滤器(_not_divisible(3), _odd_generator())).
当运行宁"yield n"时,正在生成下一个数字25并检查可整除性,而_not_divisible return 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
通过调用 next(<filter B>)
获取 value
<filter B>:1
通过调用 next(<filter C>)
获取 value
<filter C>:1
通过调用 next(<odd_numbers @ x=7>)
获取 value
<odd_numbers @ x=7>
将 x+=2
增加到 x=9
并产生它
<filter C>:2
测试_not_divisible(n=3)(9)
发现无效
<filter C>:3
被 跳过 并且循环继续
<filter C>:1
通过调用 next(<odd_numbers @ x=9>)
获取 value
<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()
周围,还有其他层可以完成 "skip yield
and request new value
"。中间生成器在产生之前可以消耗 几个 值的一般原则保持不变。
注意:
这个问题与
核心代码其实很简单,但是我很难理解它是如何工作的。这就是我添加一些调试打印的原因。
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()
比如下面是运行ning时的一段输出:
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 应该是这样的: 过滤器(_not_divisible(23),过滤器(_not_divisible(19)...过滤器(_not_divisible(7),过滤器(_not_divisible(5),过滤器(_not_divisible(5),过滤器(_not_divisible(3), _odd_generator())).
当运行宁"yield n"时,正在生成下一个数字25并检查可整除性,而_not_divisible return 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
通过调用next(<filter B>)
获取value
<filter B>:1
通过调用next(<filter C>)
获取value
<filter C>:1
通过调用next(<odd_numbers @ x=7>)
获取value
<odd_numbers @ x=7>
将x+=2
增加到x=9
并产生它
<filter C>:2
测试_not_divisible(n=3)(9)
发现无效<filter C>:3
被 跳过 并且循环继续<filter C>:1
通过调用next(<odd_numbers @ x=9>)
获取value
<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()
周围,还有其他层可以完成 "skip yield
and request new value
"。中间生成器在产生之前可以消耗 几个 值的一般原则保持不变。