为什么在 Python 3 中 map 返回一个 map 对象而不是一个列表?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/40015439/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-19 23:04:39  来源:igfitidea点击:

Why does map return a map object instead of a list in Python 3?

pythonpython-3.x

提问by NoIdeaHowToFixThis

I am interested in understanding the new language design of Python 3.x.

我有兴趣了解Python 3.x新语言设计

I do enjoy, in Python 2.7, the function map:

我很喜欢 Python 2.7 中的函数map

Python 2.7.12
In[2]: map(lambda x: x+1, [1,2,3])
Out[2]: [2, 3, 4]

However, in Python 3.x things have changed:

然而,在 Python 3.x 中,事情发生了变化:

Python 3.5.1
In[2]: map(lambda x: x+1, [1,2,3])
Out[2]: <map at 0x4218390>

I understand the how, but I could not find a reference to the why. Why did the language designers make this choice, which, in my opinion, introduces a great deal of pain. Was this to arm-wrestle developers in sticking to list comprehensions?

我明白如何,但我找不到原因的参考。为什么语言设计者会做出这样的选择,在我看来,这会带来很大的痛苦。这是为了让开发人员坚持使用列表推导式吗?

IMO, list can be naturally thought as Functors; and I have been somehow been thought to think in this way:

IMO, list 可以很自然地被认为是Functors;我一直被认为是这样思考的:

fmap :: (a -> b) -> f a -> f b

采纳答案by RemcoGerlich

I think the reason why map still exists at allwhen generator expressionsalso exist, is that it can take multiple iterator arguments that are all looped over and passed into the function:

我想,为什么地图仍然存在的原因发电机表情也是存在的,是它可以采取多个迭代论点,都环绕在并传递给函数:

>>> list(map(min, [1,2,3,4], [0,10,0,10]))
[0,2,0,4]

That's slightly easier than using zip:

这比使用 zip 稍微容易一些:

>>> list(min(x, y) for x, y in zip([1,2,3,4], [0,10,0,10]))

Otherwise, it simply doesn't add anything over generator expressions.

否则,它不会在生成器表达式上添加任何内容。

回答by vishes_shell

Because it returns an iterator, it omit storing the full size list in the memory. So that you can easily iterate over it in the future not making any pain to memory. Possibly you even don't need a full list, but the part of it, until your condition is reached.

因为它返回一个迭代器,所以它省略了在内存中存储完整大小的列表。这样您将来就可以轻松地对其进行迭代,而不会对记忆造成任何痛苦。可能您甚至不需要完整列表,而是其中的一部分,直到达到您的条件。

You can find this docsuseful, iterators are awesome.

你会发现这个文档很有用,迭代器很棒。

An object representing a stream of data. Repeated calls to the iterator's __next__()method (or passing it to the built-in function next()) return successive items in the stream. When no more data are available a StopIterationexception is raised instead. At this point, the iterator object is exhausted and any further calls to its __next__()method just raise StopIterationagain. Iterators are required to have an __iter__()method that returns the iterator object itself so every iterator is also iterable and may be used in most places where other iterables are accepted. One notable exception is code which attempts multiple iteration passes. A container object (such as a list) produces a fresh new iterator each time you pass it to the iter()function or use it in a for loop. Attempting this with an iterator will just return the same exhausted iterator object used in the previous iteration pass, making it appear like an empty container.

表示数据流的对象。重复调用迭代器的__next__()方法(或将其传递给内置函数next())返回流中的连续项目。当没有更多数据可用时,StopIteration会引发异常。此时,迭代器对象已用尽,对其__next__()方法的任何进一步调用都会StopIteration再次引发。迭代器需要有一个__iter__()返回迭代器对象本身的方法,所以每个迭代器也是可迭代的,并且可以在大多数接受其他迭代器的地方使用。一个值得注意的例外是尝试多次迭代的代码。list每次将容器对象(例如 a )传递给iter()函数或在 for 循环中使用它。使用迭代器尝试这样做只会返回与前一次迭代中使用的相同的耗尽迭代器对象,使其看起来像一个空容器。

回答by cdarke

Guido answers this question here: "since creating a list would just be wasteful".

Guido在这里回答这个问题:“因为创建一个列表只会是浪费”。

He also says that the correct transformation is to use a regular forloop.

他还说正确的转换是使用常规for循环。

Converting map()from 2 to 3 might not just be a simple case of sticking a list( )around it. Guido also says:

map()从 2转换为 3 可能不仅仅是一个简单的例子list( )。圭多还说:

"If the input sequences are not of equal length, map()will stop at the termination of the shortest of the sequences. For full compatibility with map()from Python 2.x, also wrap the sequences in itertools.zip_longest(), e.g.

“如果输入序列的长度不相等,map()将在最短序列的终止处停止。为了与map()Python 2.x完全兼容,还将序列包装在 中itertools.zip_longest(),例如

map(func, *sequences)

becomes

变成

list(map(func, itertools.zip_longest(*sequences)))

"

回答by Chris_Rands

In Python 3 many functions (not just mapbut zip, rangeand others) return an iterator rather than the full list. You might want an iterator (e.g. to avoid holding the whole list in memory) or you might want a list (e.g. to be able to index).

在Python 3的许多功能(而不仅仅是map但是ziprange和其他人)返回一个迭代器,而不是完整的列表。您可能需要一个迭代器(例如避免将整个列表保存在内存中)或者您可能需要一个列表(例如能够索引)。

However, I think the key reason for the change in Python 3 is that while it is trivial to convert an iterator to a list using list(some_iterator)the reverse equivalent iter(some_list)does not achieve the desired outcome because the full list has already been built and held in memory.

但是,我认为 Python 3 中发生变化的关键原因是,虽然使用list(some_iterator)反向等效项将迭代器转换为列表是微不足道的,iter(some_list)但并没有达到预期的结果,因为完整的列表已经构建并保存在内存中。

For example, in Python 3 list(range(n))works just fine as there is little cost to building the rangeobject and then converting it to a list. However, in Python 2 iter(range(n))does not save any memory because the full list is constructed by range()before the iterator is built.

例如,在 Python 3 中list(range(n))工作得很好,因为构建range对象然后将其转换为列表的成本很低。但是,在 Python 2iter(range(n))中不节省任何内存,因为完整列表是在构建range()迭代器之前构建的。

Therefore, in Python 2, separate functions are required to create an iterator rather than a list, such as imapfor map(although they're not quite equivalent), xrangefor range, izipfor zip. By contrast Python 3 just requires a single function as a list()call creates the full list if required.

因此,在 Python 2 中,需要单独的函数来创建迭代器而不是列表,例如imapfor map(虽然它们并不完全等效)、xrangefor rangeizipfor zip。相比之下,Python 3 只需要一个函数,因为list()如果需要,调用会创建完整的列表。