Вопрос по map-function, list-comprehension, python – Понимание списка против карты

610

Есть ли причина предпочитать использоватьmap() над списком или наоборот? Является ли один из них в целом более эффективным или считается более питоническим, чем другой?

@ lumbric, я не уверен, но это возможно, только если лямбда используется в карте. 0xc0de
Обратите внимание, что PyLint предупреждает, если вы используете карту вместо понимания списка, см.message W0141. lumbric

Ваш Ответ

9   ответов
0

что самый питонский способ - это использовать понимание списка вместоmap а такжеfilter, Причина в том, что списки понятнее, чемmap а такжеfilter.

In [1]: odd_cubes = [x ** 3 for x in range(10) if x % 2 == 1] # using a list comprehension

In [2]: odd_cubes_alt = list(map(lambda x: x ** 3, filter(lambda x: x % 2 == 1, range(10)))) # using map and filter

In [3]: odd_cubes == odd_cubes_alt
Out[3]: True

Как видите, понимание не требует дополнительногоlambda выражения какmap необходимо. Кроме того, понимание также позволяет легко фильтровать, аmap требуетfilter разрешить фильтрацию.

84
You should use map and filter instead of list comprehensions.

objective причина, по которой вы предпочитаете их, даже если они не "Pythonic" это:
introduce a new scope.

Я был укушен этим несколько раз:

for x, y in somePoints:
    # (several lines of code here)
    squared = [x ** 2 for x in numbers]
    # Oops, x was silently overwritten!

но если бы вместо этого я сказал:

for x, y in somePoints:
    # (several lines of code here)
    squared = map(lambda x: x ** 2, numbers)

тогда все было бы хорошо.

Можно сказать, что я глуп, что использовал одно и то же имя переменной в той же области видимости.

Я не был т. Код был в порядке изначально - дваxне были в той же области.
Это было только после того, как яmoved внутренний блок в другом разделе кода, в котором возникла проблема (читай: проблема во время обслуживания, а не разработки), и я не ожидал этого.

Да,if you never make this mistake тогда списочные представления более элегантны.
Но по личному опыту (и по тому, как другие видят ту же ошибку), я видел, что такое случалось достаточно много раз, и я думаю, что это не стоит той боли, которую вам придется пережить, когда эти ошибки проникают в ваш код.

Conclusion:

использованиеmap а такжеfilter, Они предотвращают тонкие, трудно диагностируемые ошибки, связанные с областью действия.

Side note:

Не забудьте рассмотреть возможность использованияimap а такжеifilter (вitertools) если они подходят для вашей ситуации!

Эта ошибкаfixed в Python 3
@ Wim: А? Python 2 все еще используется во многих местах, и тот факт, что Python 3 существует, не меняет этого. И когда вы говорите «это не совсем тонкая ошибка для любого, кто использовал Python более нескольких месяцев». это предложение буквально означает «это касается только неопытных разработчиков». (явно не ты). И, к сведению, вы явно не читали ответ, потому что я сказал вbold что я былmoving, не копируя, код. Ошибки копирования и вставки одинаковы для разных языков. Этот тип ошибок является более уникальным для Python из-за его области видимости; это более тонкий & amp; Проще забыть и пропустить.
Я извиняюсь, но вы написали это в конце 2012 года, задолго до появления Python 3, и ответ читается так, как будто вы рекомендуете непопулярный стиль кодирования Python только потому, что вас укусила ошибка во время резки и Вставить код. Я никогда не претендовал на то, чтобы быть умным или опытным, я просто не согласен с тем, что смелое утверждение оправдано вашими причинами.
@wim: Это было только для Python 2, хотя это относится к Python 3, если вы хотите оставаться обратно совместимым. Я знал об этом и некоторое время использовал Python (да, больше, чем несколько месяцев), и все же это случилось со мной. Я видел, как другие, которые умнее меня, попадали в ту же ловушку. Если вы настолько умны и / или опытны, что это не является для вас проблемой, тогда я рад за вас, я не думаю, что большинство людей такие же, как вы. Если бы они были, не было бы такого желания исправить это в Python 3.
Спасибо за указание на это. Мне явно не приходило в голову, что понимание списков находится в той же области и может быть проблемой. С учетом сказанного, я думаю, что некоторые другие ответы дают понять, что понимание списка должно быть подходом по умолчанию в большинстве случаев, но это то, что нужно помнить. Это также хорошее общее напоминание о том, что функции (и, следовательно, область действия) должны быть небольшими, иметь тщательные модульные тесты и использовать операторы assert. TimothyAWiseman
15

параллельный или распределенный код, вы, вероятно, предпочтетеmap через понимание списка - поскольку большинство асинхронных, параллельных или распределенных пакетов предоставляютmap функция для перегрузки Pythonmap, Затем, передав соответствующийmap функционировать с остальным кодом, вам может не потребоваться изменить исходный последовательный код, чтобы он работал параллельно (и т. д.).

Многопроцессорный модуль Python делает это:docs.python.org/2/library/multiprocessing.html
Не могли бы вы привести пример?
14

map(lambda op1,op2: op1*op2, list1, list2)

против:

[op1*op2 for op1,op2 in zip(list1,list2)]

Я предполагаю, что zip () - это печальные и ненужные накладные расходы, которые нужно потворствовать, если вы настаиваете на использовании списочных представлений вместо карты. Было бы замечательно, если бы кто-то разъяснил это положительно или отрицательно.

Должно быть "для" не "от" в вашей второй цитате, @andz, и в @ слабом комментарии тоже. Я думал, что обнаружил новый синтаксический подход к списку пониманий ... Черт.
чтобы добавить очень поздний комментарий, вы можете сделатьzip ленивый с помощьюitertools.izip
@tcaswell Больше не требуется в Python 3000.
Я думаю, что я все еще предпочитаюmap(operator.mul, list1, list2), Именно из-за этих очень простых выражений в левой части понимание становится неуклюжим.
& quot; [op1 * op2 из op1, op2 in zip (list1, list2)] & quot; | s / form / for / И эквивалентный список без zip: (менее читаемый) [list1 [i] * list2 [i] для i в диапазоне (len (list1))]
6

map() итератор, вы должны иметь в виду, что вам нужно: итератор илиlist объект.

Как @AlexMartelli ужеупомянутый, map() быстрее, чем понимание списка, только если вы не используетеlambda функция.

Я представлю вам некоторые сравнения времени.

Python 3.5.2 and CPython
I've used Блокнот Юпитер и особенно%timeit встроенная магическая команда
Measurements: s == 1000 мс == 1000 * 1000 & # xB5; s = 1000 * 1000 * 1000 нс

Настроить:

x_list = [(i, i+1, i+2, i*2, i-9) for i in range(1000)]
i_list = list(range(1000))

Встроенная функция:

%timeit map(sum, x_list)  # creating iterator object
# Output: The slowest run took 9.91 times longer than the fastest. 
# This could mean that an intermediate result is being cached.
# 1000000 loops, best of 3: 277 ns per loop

%timeit list(map(sum, x_list))  # creating list with map
# Output: 1000 loops, best of 3: 214 µs per loop

%timeit [sum(x) for x in x_list]  # creating list with list comprehension
# Output: 1000 loops, best of 3: 290 µs per loop

lambda функция:

%timeit map(lambda i: i+1, i_list)
# Output: The slowest run took 8.64 times longer than the fastest. 
# This could mean that an intermediate result is being cached.
# 1000000 loops, best of 3: 325 ns per loop

%timeit list(map(lambda i: i+1, i_list))
# Output: 1000 loops, best of 3: 183 µs per loop

%timeit [i+1 for i in i_list]
# Output: 10000 loops, best of 3: 84.2 µs per loop

Существует также такая вещь, как выражение генератора, см.PEP-0289, Поэтому я подумал, что было бы полезно добавить его в сравнение.

%timeit (sum(i) for i in x_list)
# Output: The slowest run took 6.66 times longer than the fastest. 
# This could mean that an intermediate result is being cached.
# 1000000 loops, best of 3: 495 ns per loop

%timeit list((sum(x) for x in x_list))
# Output: 1000 loops, best of 3: 319 µs per loop

%timeit (i+1 for i in i_list)
# Output: The slowest run took 6.83 times longer than the fastest. 
# This could mean that an intermediate result is being cached.
# 1000000 loops, best of 3: 506 ns per loop

%timeit list((i+1 for i in i_list))
# Output: 10000 loops, best of 3: 125 µs per loop
You need list object:

Используйте список, понимание, если это пользовательская функция, используйтеlist(map()) если есть встроенная функция

You don't need list object, you just need iterable one:

Всегда используйтеmap()!

567

map может быть микроскопически быстрее в некоторых случаях (когда вы НЕ делаете лямбду для этой цели, а используете ту же функцию в map и listcomp). Понимание списка может быть быстрее в других случаях, и большинство (не все) питонисты считают их более прямыми и понятными.

Пример крошечного преимущества скорости при использовании точно такой же функции:

$ python -mtimeit -s'xs=range(10)' 'map(hex, xs)'
100000 loops, best of 3: 4.86 usec per loop
$ python -mtimeit -s'xs=range(10)' '[hex(x) for x in xs]'
100000 loops, best of 3: 5.58 usec per loop

Пример того, как сравнение производительности полностью меняется, когда карта нуждается в лямбда-выражении:

$ python -mtimeit -s'xs=range(10)' 'map(lambda x: x+2, xs)'
100000 loops, best of 3: 4.24 usec per loop
$ python -mtimeit -s'xs=range(10)' '[x+2 for x in xs]'
100000 loops, best of 3: 2.32 usec per loop
Не для того, чтобы разбираться с бесконечными точками стиля Алекса, но иногда мне кажется, что карту легче читать: data = map (str, some_list_of_objects). Некоторые другие ... operator.attrgetter, operator.itemgetter и т. Д.
map(operator.attrgetter('foo'), objs) легче читать, чем[o.foo for foo in objs] ?!
Да, действительно, наше внутреннее руководство по стилю Python в действии явно рекомендует списки компоновки против карты и фильтра (даже не упоминая крошечную, но измеримую карту улучшения производительности, которая может дать в некоторых случаях ;-).
Я думаю, что @GreggLind имеет точку зрения, с егоstr() пример, хотя.
@ Алекс: Я предпочитаю не вводить ненужные имена, какo здесь, и ваши примеры показывают, почему.
15

что понимание списка обычно более выразительно в отношении того, что я пытаюсь сделать, чемmap - они оба делают это, но первое спасает умственную нагрузку от попыток понять, что может быть сложнымlambda выражение.

Там также есть интервью где-то (я не могу найти его от руки), где Гвидо перечисляетlambdas и функциональные функции как вещь, о которой он больше всего сожалеет о принятии в Python, так что вы можете сделать аргумент, что они непиратонны в силу этого.

Интервью, о котором вы думаете, это:amk.ca/python/writing/gvr-interviewгде Гвидо говорит"Sometimes I've been too quick in accepting contributions, and later realized that it was a mistake. One example would be some of the functional programming features, such as lambda functions. lambda is a keyword that lets you create a small anonymous function; built-in functions such as map, filter, and reduce run a function over a sequence type, such as a list."
& GT; Гидо. Что является еще одним доказательством того, что Гвидо не в своем уме. Конечноlambdaбыли сделаны настолько неубедительными (без заявлений ...), что их трудно использовать и в любом случае они ограничены.
Да, вздох, но первоначальное намерение Гвидо полностью удалить лямбду в Python 3 получило массу лоббирования против нее, поэтому он вернулся к ней, несмотря на мою решительную поддержку - ну, думаю, лямбда слишком удобна во многихSIMPLE случаи, единственная проблема заключается в том, когда он выходит за пределыSIMPLE или получает имя (в последнем случае это глупый дубликат определения def! -).
@ Алекс, у меня нет вашего многолетнего опыта, но я видел гораздо более сложное понимание списков, чем лямбды. Конечно, злоупотреблять языковыми особенностями всегда трудно соблазн. Интересно, что составления списков (эмпирически) кажутся более склонными к злоупотреблениям, чем лямбды, хотя я не уверен, почему так должно быть. Я также укажу, что "хромает" не всегда плохая вещь. Сокращение объема «действий, которые может выполнять эта строка» иногда может облегчить читателю. Например,const Ключевое слово в C ++ - это триумф в этом направлении.
38

map и понимание списка ведет себя совсем по-другому в языке Python 3. Взгляните на следующую программу Python 3:

def square(x):
    return x*x
squares = map(square, [1, 2, 3])
print(list(squares))
print(list(squares))

Вы можете ожидать, что он напечатает строку «[1, 4, 9]» дважды, но вместо этого он печатает «[1, 4, 9]» с последующим "[]". Первый раз, когда вы смотрите наsquares Кажется, он ведет себя как последовательность из трех элементов, но второй раз как пустой.

На языке Python 2map возвращает простой старый список, так же как и списочные выражения на обоих языках. Суть в том, что возвращаемое значениеmap в Python 3 (иimap в Python 2) это не список - это итератор!

Элементы потребляются, когда вы перебираете итератор в отличие от того, когда вы перебираете список. Вот почемуsquares выглядит пустым в последнемprint(list(squares)) линия.

Подвести итоги:

When dealing with iterators you have to remember that they are stateful and that they mutate as you traverse them. Lists are more predictable since they only change when you explicitly mutate them; they are containers. And a bonus: numbers, strings, and tuples are even more predictable since they cannot change at all; they are values.
это, вероятно, лучший аргумент для понимания списка. Карта питонов - это не функциональная карта, а искалеченный рыжий пасынок функциональной реализации. Очень грустно, потому что я действительно не люблю понимания.
Вы хотите сказать, что карта возвращает итеративный, а не итератор.
Я думаю, что я хочу дляmap создать структуру данных, а не итератор. Но, может быть, ленивые итераторы проще, чем ленивые структуры данных. Пища для размышлений. Спасибо @MnZrK
@ semiomant Я бы сказал, что lazy map (как в python3) более «функциональный». чем нетерпеливая карта (как в python2). Например, карта в Haskell ленива (ну, все в Haskell ленива ...). В любом случае, ленивая карта лучше подходит для связывания карт - если у вас есть карта, примененная к карте, примененная к карте, у вас есть список для каждого из промежуточных вызовов карты в python2, тогда как в python3 у вас есть только один результирующий список, так что он более эффективен для памяти ,
406

Cases

Common case: Almost always, you will want to use a list comprehension in python because it will be more obvious what you're doing to novice programmers reading your code. (This does not apply to other languages, where other idioms may apply.) It will even be more obvious what you're doing to python programmers, since list comprehensions are the de-facto standard in python for iteration; they are expected. Less-common case: However if you already have a function defined, it is often reasonable to use map, though it is considered 'unpythonic'. For example, map(sum, myLists) is more elegant/terse than [sum(x) for x in myLists]. You gain the elegance of not having to make up a dummy variable (e.g. sum(x) for x... or sum(_) for _... or sum(readableName) for readableName...) which you have to type twice, just to iterate. The same argument holds for filter and reduce and anything from the itertools module: if you already have a function handy, you could go ahead and do some functional programming. This gains readability in some situations, and loses it in others (e.g. novice programmers, multiple arguments)... but the readability of your code highly depends on your comments anyway. Almost never: You may want to use the map function as a pure abstract function while doing functional programming, where you're mapping map, or currying map, or otherwise benefit from talking about map as a function. In Haskell for example, a functor interface called fmap generalizes mapping over any data structure. This is very uncommon in python because the python grammar compels you to use generator-style to talk about iteration; you can't generalize it easily. (This is sometimes good and sometimes bad.) You can probably come up with rare python examples where map(f, *lists) is a reasonable thing to do. The closest example I can come up with would be sumEach = partial(map,sum), which is a one-liner that is very roughly equivalent to:

def sumEach(myLists):
    return [sum(_) for _ in myLists]
Just using a for-loop: You can also of course just use a for-loop. While not as elegant from a functional-programming viewpoint, sometimes non-local variables make code clearer in imperative programming languages such as python, because people are very used to reading code that way. For-loops are also, generally, the most efficient when you are merely doing any complex operation that is not building a list like list-comprehensions and map are optimized for (e.g. summing, or making a tree, etc.) -- at least efficient in terms of memory (not necessarily in terms of time, where I'd expect at worst a constant factor, barring some rare pathological garbage-collection hiccuping).

"Pythonism"

Мне не нравится слово "pythonic" потому что я не считаю, что питонический всегда элегантен в моих глазах. тем не менее,map а такжеfilter и аналогичные функции (например, очень полезныеitertools модуль), вероятно, считаются непифоническими с точки зрения стиля.

Laziness

С точки зрения эффективности, как и большинство функциональных конструкций программирования,MAP CAN BE LAZYи на самом деле ленив в питоне. Это означает, что вы можете сделать это (вpython3) и ваш компьютер не исчерпает память и потеряет все ваши несохраненные данные:

>>> map(str, range(10**100))
<map object at 0x2201d50>

Попробуйте сделать это с пониманием списка:

>>> [str(n) for n in range(10**100)]
# DO NOT TRY THIS AT HOME OR YOU WILL BE SAD #

Обратите внимание, что списочные представления также ленивы, ноpython has chosen to implement them as non-lazy, Тем не менее, Python поддерживает ленивые списки в форме выражений генератора, как показано ниже:

>>> (str(n) for n in range(10**100))
<generator object <genexpr> at 0xacbdef>

Вы можете в основном думать о[...] синтаксис как передача в выражении генератора в конструктор списка, какlist(x for x in range(5)).

Brief contrived example

from operator import neg
print({x:x**2 for x in map(neg,range(5))})

print({x:x**2 for x in [-y for y in range(5)]})

print({x:x**2 for x in (-y for y in range(5))})

Понимания списков не ленивы, поэтому могут потребовать больше памяти (если вы не используете генератор пониманий). Квадратные скобки[...] часто делают вещи очевидными, особенно когда в беспорядке скобок. С другой стороны, иногда вы становитесь многословным, как печатать[x for x in..., До тех пор, пока вы сохраняете свои переменные итератора короткими, списки обычно более понятны, если вы не делаете отступ в своем коде. Но вы всегда можете сделать отступ для своего кода.

print(
    {x:x**2 for x in (-y for y in range(5))}
)

или разбить вещи:

rangeNeg5 = (-y for y in range(5))
print(
    {x:x**2 for x in rangeNeg5}
)

Efficiency comparison for python3

map сейчас лень

% python3 -mtimeit -s 'xs=range(1000)' 'f=lambda x:x' 'z=map(f,xs)'
1000000 loops, best of 3: 0.336 usec per loop            ^^^^^^^^^

Therefore if you will not be using all your data, or do not know ahead of time how much data you need, map in python3 (and generator expressions in python2 or python3) will avoid calculating their values until the last moment necessary. Usually this will usually outweigh any overhead from using map. The downside is that this is very limited in python as opposed to most functional languages: you only get this benefit if you access your data left-to-right "in order", because python generator expressions can only be evaluated the order x[0], x[1], x[2], ....

Однако давайте скажем, что у нас есть готовая функцияf мы хотели быmapи мы игнорируем леньmap немедленно заставляя оценку сlist(...), Мы получаем очень интересные результаты:

% python3 -mtimeit -s 'xs=range(1000)' 'f=lambda x:x' 'z=list(map(f,xs))'                                                                                                                                                
10000 loops, best of 3: 165/124/135 usec per loop        ^^^^^^^^^^^^^^^
                    for list(<map object>)

% python3 -mtimeit -s 'xs=range(1000)' 'f=lambda x:x' 'z=[f(x) for x in xs]'                                                                                                                                      
10000 loops, best of 3: 181/118/123 usec per loop        ^^^^^^^^^^^^^^^^^^
                    for list(<generator>), probably optimized

% python3 -mtimeit -s 'xs=range(1000)' 'f=lambda x:x' 'z=list(f(x) for x in xs)'                                                                                                                                    
1000 loops, best of 3: 215/150/150 usec per loop         ^^^^^^^^^^^^^^^^^^^^^^
                    for list(<generator>)

Результаты представлены в виде AAA / BBB / CCC, где A была выполнена на рабочей станции Intel около 2010 года с python 3.?.?, А B и C были выполнены на рабочей станции AMD около 2013 года с python 3.2.1, с совершенно другим оборудованием. В результате получается, что представления карт и списков сопоставимы по производительности, что сильнее всего зависит от других случайных факторов. Единственное, что мы можем сказать, это то, что, как ни странно, мы ожидаем, что списки[...] работать лучше, чем выражения генератора(...), map ТАКЖЕ более эффективен, чем выражения генератора (опять же при условии, что все значения оценены / использованы).

Важно понимать, что эти тесты предполагают очень простую функцию (тождественную функцию); однако это хорошо, потому что если бы функция была сложной, то потери производительности были бы незначительными по сравнению с другими факторами в программе. (Это может быть интересно проверить с другими простыми вещами, такими какf=lambda x:x+x)

Если вы разбираетесь в чтении сборки Python, вы можете использоватьdis модуль, чтобы увидеть, действительно ли это происходит за кулисами:

>>> listComp = compile('[f(x) for x in xs]', 'listComp', 'eval')
>>> dis.dis(listComp)
  1           0 LOAD_CONST               0 (<code object <listcomp> at 0x2511a48, file "listComp", line 1>) 
              3 MAKE_FUNCTION            0 
              6 LOAD_NAME                0 (xs) 
              9 GET_ITER             
             10 CALL_FUNCTION            1 
             13 RETURN_VALUE         
>>> listComp.co_consts
(<code object <listcomp> at 0x2511a48, file "listComp", line 1>,)
>>> dis.dis(listComp.co_consts[0])
  1           0 BUILD_LIST               0 
              3 LOAD_FAST                0 (.0) 
        >>    6 FOR_ITER                18 (to 27) 
              9 STORE_FAST               1 (x) 
             12 LOAD_GLOBAL              0 (f) 
             15 LOAD_FAST                1 (x) 
             18 CALL_FUNCTION            1 
             21 LIST_APPEND              2 
             24 JUMP_ABSOLUTE            6 
        >>   27 RETURN_VALUE

& # XA0;

>>> listComp2 = compile('list(f(x) for x in xs)', 'listComp2', 'eval')
>>> dis.dis(listComp2)
  1           0 LOAD_NAME                0 (list) 
              3 LOAD_CONST               0 (<code object <genexpr> at 0x255bc68, file "listComp2", line 1>) 
              6 MAKE_FUNCTION            0 
              9 LOAD_NAME                1 (xs) 
             12 GET_ITER             
             13 CALL_FUNCTION            1 
             16 CALL_FUNCTION            1 
             19 RETURN_VALUE         
>>> listComp2.co_consts
(<code object <genexpr> at 0x255bc68, file "listComp2", line 1>,)
>>> dis.dis(listComp2.co_consts[0])
  1           0 LOAD_FAST                0 (.0) 
        >>    3 FOR_ITER                17 (to 23) 
              6 STORE_FAST               1 (x) 
              9 LOAD_GLOBAL              0 (f) 
             12 LOAD_FAST                1 (x) 
             15 CALL_FUNCTION            1 
             18 YIELD_VALUE          
             19 POP_TOP              
             20 JUMP_ABSOLUTE            3 
        >>   23 LOAD_CONST               0 (None) 
             26 RETURN_VALUE

& # XA0;

>>> evalledMap = compile('list(map(f,xs))', 'evalledMap', 'eval')
>>> dis.dis(evalledMap)
  1           0 LOAD_NAME                0 (list) 
              3 LOAD_NAME                1 (map) 
              6 LOAD_NAME                2 (f) 
              9 LOAD_NAME                3 (xs) 
             12 CALL_FUNCTION            2 
             15 CALL_FUNCTION            1 
             18 RETURN_VALUE 

Кажется, лучше использовать[...] синтаксис, чемlist(...), К сожалениюmap Класс немного непрозрачен для разборки, но мы можем сделать это с помощью нашего теста скорости.

Верьте или нет, некоторые «начинающие программисты» Студенты сначала изучают функциональный язык. Не обязательно плохо.
@SteveJessop: На самом деле,Guido though,t dropping map/filter was a great idea for Python 3и только восстание других Pythonistas держало их во встроенном пространстве имен (покаreduce был перемещен вfunctools). Лично я не согласен (map а такжеfilter хорошо с предопределенными, особенно встроенными, функциями, просто никогда не используйте их, еслиlambda было бы необходимо), но GvR в основном называл их не Pythonic в течение многих лет.
@ShadowRanger: правда, но GvR когда-либо планировал удалитьitertools? Часть, которую я цитирую из этого ответа, является основным утверждением, которое смущает меня. Я не знаю, в его ли идеальном мире,map а такжеfilter будет двигаться кitertools (или жеfunctools) или иди целиком, но в зависимости от того, что случится, однажды скажут, чтоitertools является непифоническим во всей полноте, тогда я действительно не знаю, что такое "питонический" должно означать, но я не думаю, что это может быть что-то похожее на то, что GvR рекомендует людям использовать.
@SteveJessop: я только обращалсяmap/filterнеitertools, Функциональное программирование отлично Pythonic (itertools, functools а такжеoperator все были разработаны специально для функционального программирования, и я все время использую функциональные идиомы в Python), иitertools обеспечивает функции, которые могут быть проблематичны для реализации самим собой, в частностиmap а такжеfilter избыточность выражений генератора, которые заставили Гвидо ненавидеть их.itertools всегда было хорошо.
«Очень полезный модуль itertools [вероятно] считается непитоническим с точки зрения стиля». Хм. Мне не нравится термин «Pythonic» либо, так что в некотором смысле меня не волнует, что это значит, но я не думаю, что это справедливо по отношению к тем, кто его использует, сказать, что в соответствии с «Pythonicness» встроенные командыmap а такжеfilter вместе со стандартной библиотекойitertools по своей сути плохой стиль. Если GvR на самом деле не говорит, что они были либо ужасной ошибкой, либо исключительно для производительности, единственным естественным выводом, если это то, что "Pythonicness" говорит это забыть об этом как о глупце ;-)

Похожие вопросы