我有一个关于Python(3)在计算多个地图时如何在内部循环的问题。这是个废话的例子:
from random import randint
A = [randint(0,20) for _ in range(100)]
map1 = map(lambda a: a+1, A)
map2 = map(lambda a: a-1, map1)
B = list(map2)
因为map()
产生了一个惰性表达式,在调用list(map2)
之前,实际上没有任何计算,对吗?
当它最终完成计算时,更类似于以下哪种方法?
循环方法1:
A = [randint(0,20) for _ in range(100)]
temp1 = []
for a in A:
temp1.append(a+1)
B = []
for t in temp1:
B.append(t-1)
循环方法2:
A = [randint(0,20) for _ in range(100)]
B = []
for a in A:
temp = a+1
B.append(temp-1)
还是以完全不同的方式进行计算?
答案 0 :(得分:1)
通常,map()
函数会生成一个生成器,该生成器反过来不会生成任何输出或计算任何东西,除非明确要求。将生成器转换为列表本质上类似于向其询问下一个元素,直到没有下一个元素为止。
我们可以在命令行上做一些实验,以了解更多信息:
>>> B = [i for i in range(5)]
>>> map2 = map(lambda b:2*b, B)
>>> B[2] = 50
>>> list(map2)
[0, 2, 100, 6, 8]
我们可以看到,即使在创建生成器之后修改B
,我们的更改仍会反映在生成器的输出中。因此,似乎map
保留了对原始可迭代对象的引用,并且仅在被要求时一次计算一个值。
在您的示例中,这意味着过程如下:
A = [2, 4, 6, 8, 10]
b = list(map2)
b[0] --> next(map2) = (lambda a: a-1)(next(map1))
--> next(map1) = (lambda a: a+1)(next(A))
--> next(A) = A[0] = 2
--> next(map1) = 2+1 = 3
--> next(map2) = 3-1 = 2
...
用人类的术语来说,map2
的下一个值是通过询问map1
的下一个值来计算的。而那个是根据您最初设置的A
计算出来的。
答案 1 :(得分:0)
可以通过在有副作用的函数上使用map
来进行调查。一般来说,您不应该为真正的代码执行此操作,但是对于调查行为是很好的。
def f1(x):
print('f1 called on', x)
return x
def f2(x):
print('f2 called on', x)
return x
nums = [1, 2, 3]
map1 = map(f1, nums)
map2 = map(f2, map1)
for x in map2:
print('printing', x)
输出:
f1 called on 1
f2 called on 1
printing 1
f1 called on 2
f2 called on 2
printing 2
f1 called on 3
f2 called on 3
printing 3
因此,每个函数都可能在最晚被调用;直到循环以数字1结束,f1(2)
才被调用。直到循环需要映射中的第二个值时,数字2才需要做。