如何解决python中可迭代对象的有效重用 警告
假设我有一个返回 100 个值的迭代器。在某些不可预测的时刻,值从一个类别切换到另一个类别(在这种情况下,ints 到 strs),并且执行的操作也需要更改(更新变量以打印字符数)。
我猜最基本的示例代码是这样的:
query(query:string):string {
var response = "No response ...";
var sendrequest = (query:string):Promise<string> => {
return new Promise( (resolve,reject) => {
this.connection.query(query,(err:string,result:string) => {
if (err) { reject(err); } else { resolve(result); }
});
});
}
sendrequest(query).then( (result:string) => {
console.log("Résultat :" + result);
return result;
});
return response;
}
这看起来很有效,但 if 语句似乎也浪费在最后 59 或 60 个条目上,因为我们可以确定项目的类型不会恢复为 int。
这里有一个变体,其中使用了两个不同的套件,因此最后一个条目不需要 def perform_operations(iterable):
most_recent_int = None
for item in iterable:
if type(item) is int:
most_recent_int = item
else:
print(f"int of {len(item)} characters")
return most_recent_int
iterable = list(range(100,140)) + [str(i) for i in range(60)]
print(f"most recent int: {perform_operations(iterable)}")
语句:
if
这看起来应该更有效率。
我能想到的唯一可能执行更少的操作并且可能被更快地解释的是:
def perform_operations(iterable):
most_recent_int = None
for item in (iterator := iter(iterable)):
if type(item) is int:
most_recent_int = item
else:
print(f"int of {len(item)} characters")
break
for remaining_str_item in iterator:
print(f"int of {len(remaining_str_item)} characters")
return most_recent_int
iterable = list(range(100,140)) + [str(i) for i in range(60)]
print(f"most recent int: {perform_operations(iterable)}")
或者:
def perform_operations(iterable):
most_recent_int = None
for item in (iterator := iter(iterable)):
if type(item) is int:
most_recent_int = item
else:
break
while True:
print(f"int of {len(item)} characters")
try:
item = next(iterator)
except stopiteration:
break
return most_recent_int
iterable = list(range(100,140)) + [str(i) for i in range(60)]
print(f"most recent int: {perform_operations(iterable)}")
对最有效的解决方案感兴趣,但也对惯用和先例的解决方案感兴趣。
解决方法
在示例情况下,条件类型检查非常快,完全没有必要使用更复杂的解决方案。
但是,假设您有一个迭代器,它昂贵区分X
和Y
这两个类别,在这种情况下,最有效的解决方案是尝试最少的歧视。假设:
- 我们不受内存限制,可以将可迭代对象冻结为
list
L
;和 - 我们有一个谓词
is_y
,如果值在类别True
中则返回Y
,否则返回False
那么您可以将冻结的 L
视为在 p
下排序的列表。在这种情况下,确定类别在哪里从 X
变为 Y
的问题简化为二分搜索。
所以......在即将到来的 Python 3.10 中,bisect.bisect
最终获得了一个 key
参数:
# freeze the iterable
frozen = list(iterable)
# find the position such that frozen[:pos] are all category X
pos = bisect.bisect_left(frozen,key=is_y)
# then proceed to deal with each half as you wish
for x in frozen[:pos]:
do_x(x)
for y in frozen[pos:]:
do_y(y)
在 Python 3.10 之前,bisect
不支持 key
参数。在这种情况下,您可以简单地将每个对象包装起来以支持 __lt__
,其中该实现只计算包装对象上的反向谓词。
class wrapper:
def __init__(self,underlying):
self.underlying = underlying
def __lt__(self,other):
return not is_y(self.underlying)
如果您内存受限,例如迭代可能非常大,那么这种方法仍然可以迭代使用:
- 读入固定大小的缓冲区;
- 尝试对该缓冲区执行
bisect_left
,如果返回值为len(buffer)
,则您尚未到达类别切换点。
警告
这种情况在实践中似乎极不可能,几乎总是通过 if
或 try: ... except ...
进行类别歧视的成本很低,并且担心它肯定会过早地优化代码以使其不可读且难以推理约。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。