【问题标题】:Python - 'append' VS '+=' efficiencyPython - 'append' VS '+=' 效率
【发布时间】:2020-01-04 22:00:16
【问题描述】:

我需要遍历一个大型数据集,并将我的结果存储在一个列表中。这是代码:

results = []
n=10000    
for i in range(1,n):
    text = requests.get("""https://www.chess.com/games/archive/eono619gameOwner=other_game&gameTypes%5B0%5D=chess960&gameTypes%5B1%5D=daily&gameType=live&page{}""".format(i)).text
    result = BeautifulSoup(text, 'html.parser')

现在要填充我的列表,我可以这样做:

   results += result

或:

   results.append(result)

在处理大型数据集时有什么更有效的方法吗?如果有,为什么?

【问题讨论】:

标签: python list


【解决方案1】:

我会改用列表推导式。

url = "https://www.chess.com/games/archive/eono619"
params = {
  'gameOwner': 'other_game',
  'gameTypes[0]': 'chess',
  'gameTypes[1]': 'daily',
  'gameType': 'live'
}
results = [BeautifulSoup(requests.get(url, params={**params, 'page': i}).text, 'html.parser') for i in range(1,n)]

尽管这在复杂性方面推动了它。 (此外,在尝试使用 BeautifulSoup 解析响应之前,您没有机会检查您的请求是否成功)。否则,请使用append。

results = []
for i in range(1,n):
    response = requests.get(url, params={**params, 'page': i})
    # TODO Make sure you got a 200 response first
    result = BeautifulSoup(response.text, 'html.parser')
    results.append(result)

【讨论】:

  • 不错。特别是因为列表是固定长度的
【解决方案2】:

对于初学者来说,results += result不等同于results.append(result)。它恰好起作用,因为result 是可迭代的,但会有效地将所有对象扁平化在一起。换句话说,+= 是 list.extend 的更受限制的等价物,而不是 list.append。后者更接近results += [result],显然效率较低。

由于您有固定数量的对象,因此 @chepner's answer 建议的列表理解非常好。

对于生成可变数量的对象的情况,我建议使用带有生成器表达式的collections.deque。这对于长序列尤其重要。附加到list 被摊销以具有长期的O(n) 重新分配行为,但这是一个缓慢的O(n),并且在短期内非常糟糕。 deques 比这快得多,只要知道长度就可以变成一个单分配的列表。

from collections import deque

template = 'https://www.chess.com/games/archive/eono619?gameOwner=other_game&gameTypes%5B0%5D=chess960&gameTypes%5B1%5D=daily&gameType=live&page={}'
results = deque(BeautifulSoup(template.format(i), 'html.parser') for i in range(1, n))
results = list(results)

【讨论】:

  • @StefanPochmann。这可能是因为该对象是可迭代的。该列表将不与附加的列表相同。
  • @StefanPochmann。话虽如此,感谢您的发现:我将答案固定为包括在内。
  • 你有deque更快的例子吗?我会觉得这很令人惊讶,我刚刚做了一个测试,[x for x in range(1000000)] 比deque(x for x in range(1000000)) 快大约 1.5 倍。
  • 我还尝试了[x for x in X if x] 和deque(x for x in X if x) 和X = [random.choice((True, False)) for _ in range(1000000)],列表理解速度也快了很多。
  • @StefanPochman。无论条件如何,我认为对于支持len(或者实际上是正确的__len_hint__)的可迭代对象来说,双端队列都不会更快,因为列表理解总是可以预先分配上限。将X 变成一个生成器,看看是否有区别(将[] 替换为(),并且不要忘记在运行之间重新初始化)。
猜你喜欢
  • 2013-05-06
  • 2013-01-04
  • 1970-01-01
  • 2012-07-09
  • 2021-04-21
  • 2011-03-22
  • 2017-10-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多