python - 在 iter(function, sentinel) 中更改函数的参数
问题描述
在观看了 pycon 的 Raymond Hettinger 讲座后,他展示了“do while loop”的更好方法
blocks = []
while True:
block = f.read(32)
if block == '':
break
blocks.append(block)
等于:
blocks = []
for block in iter(partial(f.read, 32), ''):
blocks.append(block)
代码中有相同的结构。但是,如果需要更改 iter 内部函数的参数,它就不能“正确”工作。
def get_data_from_user(user, type, token):
data = []
url = f'https://api.github.com/users/{user}/{type}?access_token={token}&page='
i = 1
while True:
a = get_json_from(url + str(i))
if not a:
break
data.extend(a)
i += 1
return data
i = 1
data = []
for piece in iter(partial(get_json_from, url+str(i)), False):
data.append(piece)
i += 1
有没有办法让它工作?
解决方案
您遗漏了一个重点:iter()
采用静态可调用对象,其中参数不能更改,但重复调用以f.read()
返回不同的值。iter()
具有两个参数的函数将重复调用partial(f.read, 32)
(so f.read(32)
),直到返回值与标记值匹配,这使得在循环中从文件中读取有效。
您的get_json_from()
功能不会这样做。使用相同的参数重复调用get_json_from()
不会改变返回值,因为get_json_from()
没有任何状态可以依赖。
您的参数不是动态的,url + str(i)
作为参数传入也不会i
从循环中获取,因为partial()
只记录一次值:
>>> from functools import partial
>>> i = 42
>>> p = partial(str, i + 10)
>>> p.args
(52,)
>>> i = 81
>>> p.args
(52,)
>>> p()
'52'
i + 10
表达不是“活的” ;结果计算一次并传递给partial()
as 52
;在调用对象之前i
设置为没有关系。81
partial()
get_json_from()
您可以使用可调用对象,该对象在每次调用时重新计算参数;一个 lambda 表达式会做到这一点(从父作用域获取url
和作为闭包):i
for part in iter(lambda: get_json_from(url + str(i)), None):
# ...
这会url + str(i)
在每次lambda
调用对象时进行计算。我假设在 url 不存在时get_json_from()
返回,而不是.None
False
i
但是,在您的情况下,您可以通过使用生成器函数将“状态”(如更改值)绑定到可迭代对象,使代码更清晰:
def gen_data_from_user(user, type, token):
url = f'https://api.github.com/users/{user}/{type}?access_token={token}&page='
i = 1
while True:
a = get_json_from(url + str(i))
if not a:
break
yield a
i += 1
在生成器函数中,代码会暂停,直到您开始迭代调用函数返回的对象。迭代时,代码会一直运行,直到yield
遇到下一个表达式,此时函数代码会再次停止,并为您提供表达式的值。
所以在上面,循环gen_data_from_user(....)
会给你每个循环a
。while True:
该函数将状态保持在局部变量之间,因此在下次取消暂停代码时使用i
(以及)。url
然后你可以使用:
for piece in gen_data_from_user(...):
# ...
不需要iter()
,上面的内容比iter(lambda: ..., None)
定义要清晰得多。
推荐阅读
- github - 找不到主机 src.springframework.org
- spring - 跨两个数据源的事务管理(ChainedTransactionManager) - SpringBoot
- android - 想要将缩略图添加到 videoview。在安卓工作室
- javascript - 如何使用 Material-UI Autocomplete 组件选择多个选项并添加新选项?
- ms-word - 您可以根据 MS Word 中另一个单元格的内容为一个单元格着色吗?
- logging - 是否可以在 GLib 新结构化日志记录中为每个域/日志级别设置不同的写入器函数?
- javascript - 如何以随机顺序运行一组函数
- php - 与 SQL Server 连接的 PHP 登录表单不起作用
- javascript - 我的页面上未应用比例属性(anime.js)
- c# - 无法将 IApplicationDbContext 注入 .net 核心中的服务类