[求助] Python 在列表推导时使用( )和 [] 差别那么大?

正在尝试获取一些代理 ip,在清洗数据的时候发现了一个百思不得其解的东西。如下图所示:

在图中箭头标注的地方,用列表[],则终端输出的内容是正常的,符合预期的: 正常

但如果将图中箭头标注的地方,换成 tuple(),终端输出的内容就不知道是什么东西了: 不正常

get_ips()返回的是自建的一个类 ResultContainer,可以看成是一个列表,其他部分的代码没啥特殊的。

请教大神这是什么原因啊!!!求教!


[求助] Python 在列表推导时使用( )和 [] 差别那么大?

8 回复

而且也仅在这里遇到了这样的情况,在其他地方用[(i,i) for i in range(100)]这样推导是没问题的


在列表推导式里,用 [] 生成的是列表(list),而用 () 生成的是生成器表达式(generator expression)。这是本质区别。

简单说,[] 会立刻计算出所有结果,并存储在内存的一个列表里。而 () 返回的是一个生成器对象,它很“懒”,只在你要下一个值的时候(比如在 for 循环里迭代,或传给 sum()list() 这类函数时)才计算一个值,并且不保存之前的值。所以生成器对处理大量数据或无限序列时能省很多内存。

看个例子就明白了:

# 列表推导式:立刻计算,内存里有完整列表
list_comp = [x**2 for x in range(5)]
print(list_comp)  # 输出: [0, 1, 4, 9, 16]
print(type(list_comp))  # <class 'list'>

# 生成器表达式:不立刻计算,返回一个生成器对象
gen_exp = (x**2 for x in range(5))
print(gen_exp)  # 输出: <generator object <genexpr> at 0x...>
print(type(gen_exp))  # <class 'generator'>

# 要得到结果,需要迭代它或转换成列表
for val in gen_exp:
    print(val, end=' ')  # 输出: 0 1 4 9 16
# 注意:生成器只能迭代一次,迭代完就空了
print(list(gen_exp))  # 输出: []

关键点

  1. 内存:列表推导式 ([]) 占内存,因为它把所有结果都存下来。生成器表达式 (()) 几乎不占内存(只占生成器对象本身那点开销),数据是即用即算、算完就丢。
  2. 速度:如果最终需要所有数据,列表推导式通常更快,因为它是批量操作。生成器表达式有每次迭代的函数调用开销,但可以“流式”处理,在数据量大或不需要全部结果时有优势。
  3. 使用场景
    • []:当你明确需要一个列表,并且数据量不大,或者需要多次访问、随机访问(如 my_list[5])时。
    • ():当数据量很大或无限,或者你只是想把结果传给另一个会迭代它的函数(如 sum(x**2 for x in range(1000000)))时,用生成器表达式可以避免创建巨大的中间列表。

一个常见的“坑”是直接把生成器表达式当元组推导式。Python 没有元组推导式,(x for x in iterable) 就是生成器表达式。要创建元组,得用 tuple()tuple(x for x in iterable)

所以,差别大是正常的,因为它们本来就是两种不同的东西。选哪个取决于你是想要一个实实在在的列表,还是一个“懒加载”的生成器。

总结:要列表用[],要生成器用()。

圆括号那个是生成器,不是推导式,没有元组推导式这种东西。

遇到不知道的东西请善用搜索,一搜索就能知道是 generator。

()的写法写出来是生成器,你用到的时候才会生成数据,不用它就不生成。
[]的写法写出来就是个列表,数据都生成好了。

大体可以理解成 range(8)list(range(8)) 的区别。

这不是 python 里最有名的特性生成器表达式吗?我严重怀疑你是怎么学 python 的。。

前面那个是生成器,不是列表推导式。。。

回到顶部