Using map with multiple args

戏子无情 提交于 2021-02-19 07:09:53

问题


Python's map can take multiple iterables, for use when the callable can accept the same number of input arguments. If the input iterables are the same length, thats behaving like the list comprehension passing in zipped arguments, e.g.:

>>> iterables = 'spam', 'eggs'
>>> map(max, *iterables)
['s', 'p', 'g', 's']
>>> [max(*a) for a in zip(*iterables)]
['s', 'p', 'g', 's']

When the input arguments are different length, it gets weird - Python 2 (docs) pads with None, but Python 3 (docs) truncates to shortest iterable.

>>> map(max, 'spam', 'potato')  # 2.x
['s', 'p', 't', 'm', 't', 'o']
>>> list(map(max, 'spam', 'potato'))  # 3.x
['s', 'p', 't', 'm']

Why is this feature existing, what's an example of a typical case where that's needed or useful? I don't know a lot about functional styles, could I be missing out on some great strengths of map that are related to the multiple arguments? And what's the rationale for the API change in 3.x?


回答1:


Regarding why map truncates in python3, this is simply because python3's map is actually itertools.imap. And the documentation says:

Like map() but stops when the shortest iterable is exhausted instead of filling in None for shorter iterables. The reason for the difference is that infinite iterator arguments are typically an error for map() (because the output is fully evaluated) but represent a common and useful way of supplying arguments to imap().

The truncation allows you to do things like map(func, itertools.repeat(5), [1,2,3]) and iterate over the result without worries. With the old map that would be an infinite loop.

One of the most significant changes in python3 is that a lot of built-in functions now return generators instead of lists, including map and zip. This "increased lazyness" changed the way these functions should be used and thus the modified behaviour.

As to why one would ever use python2's multiple-iterables to map I don't know. Sure, it's a shortcut for something like (in python3):

list(itertools.starmap(function, itertools.zip_longest(*iterables)))

This might have some corner case usage, but I've never seen it used. Probably most people don't even know that map accepts a sequence of iterables. So, AFAIK there isn't any super-power deriving from the use of multiple arguments.

As to why map is in the language, that's because map was there long before list-comprehensions. Before list-comprehensions it was quite useful for building lists. It wasn't remove for backward compatibility and because many people actually like it, although Guido did want to remove it.

To learn more about the history of map, filter and reduce and other functional aspects, read: The History of Python: Origins of Python's "Functional" Features



来源:https://stackoverflow.com/questions/20646996/using-map-with-multiple-args

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!