正确使用range(),为啥pylint会抱怨:不迭代时引用了range built-in
Posted
技术标签:
【中文标题】正确使用range(),为啥pylint会抱怨:不迭代时引用了range built-in【英文标题】:Correct use of range(), why does pylint complain: range built-in referenced when not iterating正确使用range(),为什么pylint会抱怨:不迭代时引用了range built-in 【发布时间】:2019-07-26 17:58:23 【问题描述】:使用 range() 代替列表可能非常方便且切中要害,但如果将 range() 分配给变量,pylint 会发出警告。 (范围内建非迭代)
范围对象类似于列表(具有长度、可以随机访问、可迭代等),那么是否存在此代码错误的情况?
from typing import *
def fn(a: Sequence[int]) -> None:
for x in a:
print(x)
r = range(10, 100)
fn(r)
编辑(添加):
这样做的一个动机是传递范围而不是到处传递(开始,结束)对
【问题讨论】:
没什么问题,只是不是很 Pythonic 能否请您详细说明一下?恕我直言,它简洁,利用语言和高效(与 ietuple(range(10,100))
相比)我什至可以(实际上,我认为它会更好)让 a 的类型为 Sequence[int]
而不是 Iterable
这里有些人比我更了解这一点,但我的感觉是您正在创建一个范围,然后创建一个函数来迭代它。为什么不在函数中创建它?范围的唯一用途是在迭代时。
@JoshFriedlander 什么不是 Python 的?在需要 range
对象的地方使用 range
对象是完全 Pythonic 的。我倾向于说,忽略 pylint。
@JoshFriedlander 不,range
是一个容器。它的用途不仅仅是迭代它。
【参考方案1】:
我认为 pylint 没有正确地证明这个警告是正确的。
official 文档中的理由
(在 Python 3 中返回一个迭代器)
适用于迭代器(如地图)但不适用于范围。
要轻松查看iterator
对象和non-iterator
对象之间的差异,您可以执行以下几行
r = range(5)
print(list(r)) # [0, 1, 2, 3, 4]
print(list(r)) # [0, 1, 2, 3, 4]
m = map(int, '01234')
print(list(m)) # [0, 1, 2, 3, 4]
print(list(m)) # []
iterator
消耗了元素。
但我认为这不是一个好的做法,因为您可能会想将其用作列表,在某些情况下可能会比较慢。
让我们举两个例子
r = range(500000)
l = list(r)
%%time
for i in range(200):
for k in r:
pass
# 6.7 sec on my computer
%%time
for i in range(200):
for k in l:
pass
# 4.5 sec on my computer
主要区别在于list
是加载到内存中的,迭代速度更快。
编辑:如果您正在寻找速度,您可能想要使用列表,否则您应该使用范围。
我今天早些时候在 pylint 上打开了一个issue,如果这值得拉请求,我会稍后处理
【讨论】:
不要试图变得困难或任何事情,但是“由于range
不消耗内存,您绝对应该避免将它们存储在变量中”.. 为什么?有趣的是,列表更快(我会猜到相反的情况,特别是如果实际访问的值)。其他,如果我们正在追逐内存负载 - 范围将是有益的..
range
确实 不返回迭代器 如果这是 pylint 中的理由,那么 pylint 是完全错误的。无论如何,像容器一样使用range
对象并没有错。是的,您正在用略少更快的迭代换取潜在的巨大内存节省(以及其他好东西,如恒定时间成员检查和切片)
@ttyridal 这样我会说每次都动态定义它们会更好。但你可能是对的。我将编辑我的答案:)
@juanpa.arrivillaga 我完全同意你的观点,更新以上是关于正确使用range(),为啥pylint会抱怨:不迭代时引用了range built-in的主要内容,如果未能解决你的问题,请参考以下文章
Pylint 抱怨将字符串与带有“is”的文字进行比较 [重复]
pytest 固定装置从外部范围重新定义名称 [pylint]