python - Python:生成器和过滤器如何在使用 filter() 生成素数列表的代码中工作
问题描述
注意:这个问题与在 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()
在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 之后,进入下一个循环,奇数应该是这样的: filter(_not_divisible(23),filter(_not_divisible(19) ...filter(_not_divisible(7),filter(_not_divisible(5),filter( _not_divisible(5),过滤器(_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
通过调用获取 anext(<filter B>)
<filter B>:1
value
通过调用获取 anext(<filter C>)
<filter C>:1
value
通过调用获取 anext(<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
通过调用获取 anext(<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 通过。相反,循环 in<filter C>
获取另一个值而不屈服于<filter B>
and <filter A>
。
随着越来越多filter(_not_divibible(n), ...)
的层被包裹起来_odd_number_generator()
,还有额外的层可以“跳过yield
并请求新value
”。中间生成器在产生之前可以消耗多个值的一般原则保持不变。
推荐阅读
- c - uint8_t 类型数组的元素是否总是被打包到内存的连续字节中?
- java - Jira API 自动化 - 保证 REST
- ruby-on-rails - 如何使用现有数据库启动新的 Rails 项目?
- c++ - 在尚未从模板声明的命名空间中使用函数
- testing - 使用 Appium 进行 Nativescript 本地化测试 - 文本提取
- android - 语言环境在 Android 中返回空字符串
- python - import socketio - ValueError:信号仅在主线程中有效
- postgresql - 使用包含表中的 jsonb 数据类型对第一级查询的 where 子句进行续集
- gitlab - Gitlab x jira 集成:问题不会在状态之间转换
- sql-server - 在 MSSQL 中从链接服务器 ORACLE 快速加载数据