为啥 map over 一个 iterable 返回一个一次性的 iterable?
Posted
技术标签:
【中文标题】为啥 map over 一个 iterable 返回一个一次性的 iterable?【英文标题】:Why does map over an iterable return a one-shot iterable?为什么 map over 一个 iterable 返回一个一次性的 iterable? 【发布时间】:2017-08-25 08:10:09 【问题描述】:为什么map
使用可以多次迭代的对象调用时不返回也可以多次迭代的对象?我认为后者更合理。
我的用例是我有很多data
,所以它只能被迭代。 map
(理论上)非常适合在 data
上进行操作,因为它很懒惰。但是在下面的示例中,我希望长度两次都相同。
iterable = [1,2,3,4] # this can be iterated repeatedly
m = map(lambda x:x**2, iterable) # this again should be iterable repeatedly
print(len(list(m))) # 4
print(len(list(m))) # 0
如何映射可迭代结构并返回可迭代结构?
编辑: 这是一个imho应该如何工作的例子,展示了惰性评估:
def g():
print('g() called')
data = [g, g]
# map is lazy, so nothing is called
m = map(lambda g: g(), data)
print('m: %s' % len(list(m))) # g() is called here
print('m: %s' % len(list(m))) # this should work, but doesnt
# this imap returns an iterable
class imap(object):
def __init__(self, fnc, iterable):
self.fnc = fnc
self.iterable = iterable
def __iter__(self):
return map(self.fnc, self.iterable)
# imap is lazy, so nothing is called
im = imap(lambda g: g(), data)
print('im: %s' % len(list(im))) # g() is called here
print('im: %s' % len(list(im))) # works as expected
【问题讨论】:
如果你需要使用len
,那么为什么不直接使用列表解析呢?它同样懒惰并产生永久性结果。如果您需要len
但真的想使用map
,只需在输入上调用len
而不是map
的输出。
如果您希望能够反复迭代它,为什么不然后使用列表?还是只使用列表推导?
例如,可能它消耗了太多的内存。很确定len
只是作为一个例子来表明它不能被消费两次。
【参考方案1】:
为什么当使用可以多次迭代的对象调用map时不返回也可以多次迭代的对象?
因为没有接口告诉一个对象是否可以重复迭代。 map
无法判断它正在迭代的事物是否支持重复迭代,除非 map
设法以某种方式确定此信息并发明一个 API 将其公开给用户,否则 map
用户将无法判断他们的map
对象是否支持重复迭代。
此外,随着重复迭代,需要重复函数评估或缓存结果(但如果您要缓存结果,为什么要重新设计 map
以返回一个迭代器呢?)。重复的函数评估效率低下,有潜在的危险,而且通常不是用户想要的。如果用户想再次迭代,最好让用户显式重复map
调用或显式调用list
。
如果map
对象总是只是迭代器,那就更简单了。
【讨论】:
澄清一下:x is iter(x)
可用于确认一个可迭代对象不可 可重复,但您 can't prove the converse。
@ZeroPiraeus:问题中甚至还有一个反例:问题自己的imap
类有x is not iter(x)
,但仅在底层可迭代支持的情况下才支持重复迭代。
第一段是我的问题的答案——在 python 集合中是不可能的。您的第二点是权衡所有其他实现映射的语言(Haskell、Java、Scala、Closoure 等)必须以某种方式面对和解决。我找到了 PyFunctional 库,它似乎可以满足我的需要。以上是关于为啥 map over 一个 iterable 返回一个一次性的 iterable?的主要内容,如果未能解决你的问题,请参考以下文章
[Immutable,js] Iterating Over an Immutable.js Map()
c++11中,为啥可以用const_iterator删除map/multimap中的元素