迭代多个地图
Iteration over multiple maps
我有一个问题,关于 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)
之前不会实际计算任何东西,对吗?
当它最终执行此计算时,它更类似于以下哪种方法?
循环方式一:
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)
循环方式二:
A = [randint(0,20) for _ in range(100)]
B = []
for a in A:
temp = a+1
B.append(temp-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
计算出来的。
这可以通过对具有副作用的函数使用 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
因此,每个函数都在它可能被调用的最晚时间被调用; f1(2)
在循环完成数字 1 之前不会被调用。在循环需要映射中的第二个值之前,不需要对数字 2 执行任何操作。
我有一个问题,关于 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)
之前不会实际计算任何东西,对吗?
当它最终执行此计算时,它更类似于以下哪种方法?
循环方式一:
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)
循环方式二:
A = [randint(0,20) for _ in range(100)]
B = []
for a in A:
temp = a+1
B.append(temp-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
计算出来的。
这可以通过对具有副作用的函数使用 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
因此,每个函数都在它可能被调用的最晚时间被调用; f1(2)
在循环完成数字 1 之前不会被调用。在循环需要映射中的第二个值之前,不需要对数字 2 执行任何操作。