真实情况: #

昨晚写到这样的代码

def chartoNum(s):
    dict = {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4}
    return dict[s]

def fn(x, y):
    return x * 10 + y

r = map(chartoNum, "23443")
print(list(r))
r1 = reduce(fn, r)
print(r1)

很不幸的是,报错了 -

TypeError: reduce() of empty sequence with no initial value

可是我明明给你 reduce 值了 --

我将目标锁定在 r 身上,于是将 r 替换成 map(....) 实测正常。那为什么会这样呢?

首先我们得知道 python 的迭代器 #

itertors

从中你会发现:创建一个迭代器和停止自己看吧,这里只讲一点 列表,元组,字典和集合都是可迭代的对象。它们是可迭代的容器,您可以从中获得迭代器。 (区别可迭代和迭代器) 所有这些对象都有一个 iter() 方法用于获取迭代器,然后经过 next() 去打印。 并且我们一直使用 for 去遍历一些列表元组字典,实际上就是该 for 循环创建了一个迭代器对象,并为每个循环执行 next() 方法。 所以我们才能去遍历得到值 解释器需要迭代对象 x 时,会自动调用 iter(x)

那为什么要介绍迭代器? 我们再来看下 reduce 的语法

reduce(function, iterable[, initializer])

iterable 就是可迭代的对象

对于 map 在 Python 3.x 返回迭代器。 所以我们一般需要 list(),将其返回列表,bug 就出现在这里。

!!!!!! list() 后迭代器,第一次有值,第二次就没了

list(r)  # 有值列表
list(r)  # 空列表

以至于我们再去调用 r 的时候为空,但是 print(r) 是有值的 这是为什么呢??? list() 的作用是返回列表,也就是可迭代的对象 list(r) 后再调用 next(r) 会发现报错 StopIteration

迭代器对象实现了 __next__() 方法并通过 StopIteration 异常标识迭代的完成。

这是因为 next 不到值了,这就说明了 list map 对象后指针已经到了最后一个,所以再去使用 r 是空。而 print(r) type(r) 这样内置的是重新审查了一遍整体 r,因此有值。

而 list、字符串等其它可迭代对象,却没有这样的问题,这是因为 这些部分将创建一个新的可迭代对象,然后 next 对于这些新的

而 map 本身就是迭代器!!!! list() 后返回的是本身,因此 next 自然是末尾!

于是乎,我们似乎明白了些什么 (´இ 皿 இ `)