[求助] Python 在列表推导时使用( )和 [] 差别那么大?
正在尝试获取一些代理 ip,在清洗数据的时候发现了一个百思不得其解的东西。如下图所示:
在图中箭头标注的地方,用列表[],则终端输出的内容是正常的,符合预期的:

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

get_ips()返回的是自建的一个类 ResultContainer,可以看成是一个列表,其他部分的代码没啥特殊的。
请教大神这是什么原因啊!!!求教!
[求助] Python 在列表推导时使用( )和 [] 差别那么大?
而且也仅在这里遇到了这样的情况,在其他地方用[(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)) # 输出: []
关键点:
- 内存:列表推导式 (
[]) 占内存,因为它把所有结果都存下来。生成器表达式 (()) 几乎不占内存(只占生成器对象本身那点开销),数据是即用即算、算完就丢。 - 速度:如果最终需要所有数据,列表推导式通常更快,因为它是批量操作。生成器表达式有每次迭代的函数调用开销,但可以“流式”处理,在数据量大或不需要全部结果时有优势。
- 使用场景:
- 用
[]:当你明确需要一个列表,并且数据量不大,或者需要多次访问、随机访问(如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 的。。


