【问题标题】:Does list instantiates at every iteration of python 'for' loop?list 是否在 python 'for' 循环的每次迭代中实例化?
【发布时间】:2020-03-12 10:31:44
【问题描述】:

我想知道在 for 循环中创建(实例化)和使用的 list 是否会降低我的程序的效率。

例如:

for i in range(1, 10000):
     print("This i = ", i)

请告诉我是否会生成列表 [1,2,3,...,10000](即 range(1,10000))(或实例化)在每次迭代或不。因为如果是,那么这是一个巨大的开销和低效的程序。

其实我想这样用:

with open("bbc.txt", 'w', encoding='utf-8') as bbcFile:
    for headline in BS(REQ.get("https://www.bbc.com").text, 'html.parser').find_all('div', {'class':'media__content'}):
        bbcFile.write(" ".join(headline.text.split()) + "\n\n")

【问题讨论】:

  • A range 依赖于生成器,所以不,不会生成 10000 次列表
  • 在 Python 3 中...range(...) 根本不生成列表...
  • 您的“实际”示例中没有range()。不过,BeautifulSoup 在某个时候构建内存列表。
  • @ThomasSchillaci 不完全是生成器。这是一个自定义对象,查看*.com/questions/30081275/…
  • 实际上它是一个可迭代的——但确实是一个懒惰的。

标签: python python-3.x list for-loop beautifulsoup


【解决方案1】:

在 Python for 语句中,as defined by the docs

for_stmt ::=  "for" target_list "in" expression_list ":" suite
              ["else" ":" suite]

根据上述文档,

表达式列表被评估一次;它应该产生一个可迭代的 目的。为expression_list 的结果创建一个迭代器。 然后,该套件为由提供的每个项目执行一次 迭代器,按照迭代器返回的顺序。每个项目依次是 使用标准分配规则分配给target list (参见赋值语句),然后执行suite

所以,不,您用于生成可迭代对象的任何表达式都只计算一次。你可以自己测试一下:

>>> class MyIterable:
...     def __init__(self):
...         print("Initialized")
...     def __iter__(self):
...         yield from (1,2,3)
...
>>> for x in MyIterable():
...     print(x)
...
Initialized
1
2
3
>>>

【讨论】:

    【解决方案2】:

    对于 Python 3,没有。 range(1, 10000) 创建一个范围对象,在必要时生成项目:

    >>> range(1, 10000)
    range(1, 10000)
    >>> type(range(1, 10000))
    <class 'range'>
    

    因此,内存中永远不会存储[1, ..., 10000] 列表。

    一个很好的 SO 问题是 this one,它解释了 range 对象。

    【讨论】:

    • 我认为问题在于 for-statment 中的可迭代表达式是否在每次迭代时重新评估,因此以 for x in list(range(10000)): ... 为例
    最近更新 更多