Comprehensions
The concept of “functional programming” is clearly defined in some contexts, but is also used in a less strict sense. Python is not a functional language in the strict sense, but it does support a number of functional paradigms.
In general, code is considered “Pythonic” that uses functional paradigms where they are natural, but not when they have to be forced in.
We will cover functional programming concepts more clearly later in the program, but for now, we’ll talk about the syntax for a common functional paradigm: applying an expression to all the members of a sequence to produce another sequence.
Consider this common for loop structure:
This is such a common pattern that python added syntax to directly support it. This syntax is known as “comprehensions”. The most common of which is a list comprehension, used to build up a new list. There are a couple others, which we will get too later, but they all share a similar structure.
The above structure can be expressed with a single line using a “list comprehension” like so:
Nice and clear and compact, and the use of the “list” brackets ( [. ] ) makes it clear you are making a list.
Recall what an expression is in Python: a bit of code (names and operators) that evaluates to a value. So in the beginning of a comprehension, you can put anything that evaluates to a value – and that value is what gets added to the new list. This can be a simple (or complex) math operation: x * 3 , or a function or method call: a_string.upper() , int(x) , etc. But it can not contain any statements: code that does not return a value, such as assignment ( x = 5 ), or for loops, or if blocks.
Nested Loops
What about nested for loops? Sometimes you need to build up a list by looping over two sequences like so:
This can also be expressed with a comprehension in one line:
But the two lists are not looped through in parallel. Rather, you get all combinations of the two lists – Sometimes called the “outer product”.
Note that it makes every combination of the two input lists, and thus will be len(list1) * len(list2) in size. And there is no reason for them to be the same size.
zip() with comprehensions
If you want them paired up instead, you can use zip() :
Comprehensions and map()
Comprehensions are another way of expressing the “map” pattern from functional programming.
Python does have a map() function, which pre-dates comprehensions. But it does much of the same things – and most folks think comprehensions are the more “Pythonic” way to do it. And there is nothing that can be expressed with map() that cannot be done with a comprehension. If you are not familiar with map() , you can safely skip this, but if you are:
In this case, the comprehension is a tad wordier than map() . But comprehensions really shine when you don’t already have a handy function to pass to map:
To use map() , you need a function:
There are shortcuts of course, including lambda (stay tuned for more about that):
But is that easier to read or write?
What about filter?
“filtering” is another functional concept: building a new list with only some of the elements – “filtering” out the ones you don’t want. Python has a filter() function, also pre-dating comprehensions, but you can do it with a comprehension as well, and it does the application of the expression and the filtering in one construct, rather than having to nest map and filter calls.
This supports the common case of having a conditional in the loop:
This kind of “filtering” loop can be achieved by adding a conditional to the comprehension:
This is expressing the “filter” pattern and the “map” pattern at the same time – one reason I like the comprehension syntax so much.
How do I see all the built in Exceptions?
Note that the last one was only filtering ( if "Error" in name ), without applying any expression to the items ( name for name ).
Set Comprehensions
You can do a similar thing with sets, as well:
The curly brackets ( <. >) indicate a set.
This results in the same set as this for loop:
or, indeed, the same as passing a list comp to set() .
Example: Finding all the vowels in a string…
Why did I use set(‘aeiou’) rather than just ‘aeiou’ ? … in works with strings as well, but is it efficient?
Dict Comprehensions
You can also build up a dictionary with a comprehension:
Which is the same as this for loop:
A dict comprehension also uses curly brackets like the set comprehension – Python knows it’s a dict comprehension due to the key: value construct.
Example:
A bit of History:
dict comps are not as useful as they used to be, now that we have the dict() constructor.
In the early days of Python the only way to create a dict was with a literal:
or a dict that was already populated with a bunch of data.
If you had a bunch of data in some other form, like a couple of lists, you’d need to write a loop to fill it in:
now, with dict comps, you can do:
But there is also a dict() constructor (actually the type object for dict):
dict() can take different types of arguments, and will do something different with each one.
The first option (no argument) is an empty dict – simple enough.
The option makes a dict from the contents of another dict or similar object (called a “mapping”).
The options is of interest here – it makes a dict from an iterable of key, value pairs – exactly what zip() gives you.
So we can create a dict from data like so:
Which is more compact, and arguably more clear, than the dict comprehension.
dict comps are still nice if you need to filter the results, though:
Generator Comprehensions
There is yet another type of comprehension: generator comprehensions, technically known as “generator expressions”. They are very much like a list comprehension, except that they evaluate to a lazy-evaluated “iterable”, rather than a list. That is, they generate the items on the fly.
This is useful, because we often create a comprehension simply to loop over it right away:
In this case, the list comprehension: [y**2 for y in a_sequence] iterates over a_sequence , computes the square of each item, and creates a whole new list with the new values. All this, just so it can be iterated over again right away. If the original sequence is large (or is itself a lazy-evaluated iterable), then the step of creating the extra list can be expensive and unnecessary.
Generator comprehensions, on the other hand, create an iterable that evaluates the items as they are iterated over, rather than all at once ahead of time – so the entire collection is never stored.
The syntax for a generator comprehension is the same as a list comp, except it uses regular parentheses:
So what does that evaluate to? A list comp evaluates to a list:
A generator comp evaluates to a generator:
A generator is an object that can be iterated over with a for loop, and it will return the values as they are asked for:
You will learn more about generators and other ways to make them in future lessons.
Let’s use a little function to make this clear:
It simply returns the square of the passed-in value, but prints it as it does so, so we can see when it is called.
Having a “print” in a function is a example of a “side effect” – something that is an effect of the function being called that is not reflected in the return value of that function. As a rule, it’s not a good idea to use functions with side effects in comprehensions. We’re only doing it here as a debugging aid – so we can clearly see when the function is being called.
If we use it in a list comp:
We see that test() gets called for all the values, and then a list is returned with all the results. But if we use it in a generator comprehension:
Nothing gets printed (the function has not been called) until you loop through it:
You can see that test() is getting called for each item as the loop is run.
You usually don’t assign a generator expression to a variable, but rather, loop through it right away:
When to Use What
It’s pretty simple:
If you need a list (or a set or dict) for further work, then use a list comp.
If you are going to immediately loop through the items created by the comprehension, use a generator comprehension.
The “official” term is “generator expression” – that is what you will see in the Python docs, and a lot of online discussions. I’ve used the term “generator comprehension” here to better make clear the association with list comprehensions.
References
This is a nice intro to comprehensions from Trey Hunner:
Once you’ve got the hang of it, you may want to read this so you don’t overdo it 🙂
Trey writes a lot of good stuff – I recommend browsing his site.
© Copyright 2020, University of Washington, Natasha Aleksandrova, Christopher Barker, Brian Dorsey, Cris Ewing, Christy Heaton, Jon Jacky, Maria McKinley, Andy Miles, Rick Riehle, Joseph Schilz, Joseph Sheedy, Hosung Song. Creative Commons Attribution-ShareAlike 4.0 license.
Абстракция списков (List Comprehension) в Python
Абстракция списков (или «списковое включение», англ. «List Comprehension») — это элегантный способ определения и создания списков на основе существующих списков. Синтаксис абстракции списков в Python следующий:
[выражение for элемент in список]
Примеры абстракции списков
Предположим, мы хотим разделить буквы слова human и добавить их в качестве элементов списка. Первое, что приходит на ум — это использовать цикл for.
Пример №1: Итерация по строке с помощью цикла for:
Когда мы запустим программу, результатом будет:
Однако в Python есть более простой способ решить эту проблему — использовать абстракцию списков.
Давайте посмотрим, как вышеприведенная программа может быть переписана с использованием абстракции списков.
Пример №2: Итерация по строке с помощью абстракции списков:
Когда мы запустим программу, результатом будет:
Здесь переменной h_letters присваивается новый список, который содержит элементы итерируемой строки ‘human’ . Если вы заметили, ‘human’ — это строка, а не список. В этом и заключается сила абстракции списков. Оно может определить, когда получает строку или кортеж, и работать с этим объектом как со списком.
Абстракция списков vs. Лямбда-функции
Абстракция списков не является единственным способом работы со списками. Различные встроенные функции и лямбда-функции позволяют создавать и изменять списки за меньшее количество строк кода.
Пример №3: Использование лямбда-функций внутри списка:
Обычно абстракция списков более читабельна, чем лямбда-функции. Легче понять, чего пытается добиться программист.
Условия в абстракции списков
В абстракции списков можно использовать условия для изменения существующего списка (или других кортежей).
Пример №4: Использование if в абстракции списков:
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
Список number_list будет заполнен элементами в диапазоне от 0-19, если значение элемента делится на 2.
Пример №5: Вложенный if в абстракции списков:
[0, 10, 20, 30, 40, 50, 60, 70, 80, 90]
Здесь абстракция списков проверяет:
- Делится ли y на 2 или нет?
- Делится ли y на 5 или нет?
Если y удовлетворяет обоим условиям, y добавляется в список num_list .
[‘Even’, ‘Odd’, ‘Even’, ‘Odd’, ‘Even’, ‘Odd’, ‘Even’, ‘Odd’, ‘Even’, ‘Odd’]
Здесь абстракция списков проверяет 10 чисел от 0 до 9. Если i делится на 2, то в список obj добавляется Even . Если нет, то добавляется Odd .
Вложенные циклы в абстракции списков
Предположим, нам нужно вычислить транспонирование матрицы, что требует использования вложенного цикла for.
Пример №7: Транспонирование матрицы с помощью циклов for:
Здесь используются два цикла for для нахождения транспонирования матрицы. Мы также можем выполнять вложенные итерации внутри списка. А сейчас попробуем найти транспонирование матрицы с помощью вложенного цикла внутри абстракции списков.
Пример №8: Транспонирование матрицы с помощью абстракции списков:
[[1, 3, 5, 7], [2, 4, 6, 8]]
Здесь у нас есть переменная matrix , которая имеет 4 строки и 2 столбца. Нам нужно найти транспонирование matrix . Для этого мы использовали абстракцию списков.
Примечание: Вложенные циклы в абстракции списков работают не так, как обычные вложенные циклы. В приведенной выше программе цикл for i in range(2) выполняется до row[i] for row in matrix . Следовательно, сначала переменной i присваивается значение, а затем элемент, на который указывает row[i] , добавляется в переменную transpose .
Ключевые моменты
Абстракция списков — это элегантный способ определения и создания списков на основе существующих списков.
Абстракция списков в целом компактнее и быстрее, чем обычные функции и циклы, для создания списка.
Следует избегать написания очень длинных списков в одной строке с помощью абстракции списков, чтобы код оставался читабелен.
Помните, что любую абстракцию списков можно переписать с помощью цикла for, но не каждый цикл for можно переписать с помощью абстракции списков.
List Comprehensions в Python за 5 минут
![]()
List comprehensions — это один из способов создания Pythonic-однострочников (one-liners) с итерируемыми списками.
В качестве примера рассмотрим продуктовую корзину. Вы вытаскиваете каждый товар и кладете на кассу. В таком случае, продуктовую корзину можно назвать iterable.
Разберем этот пример с помощью кода. Мы находимся в вычислительном магазине, поэтому будем покупать только числа.
Какие действия были выполнены?
- Создаем список элементов в cart
- Создаем пустой список cashier ( cashier еще не содержит элементов)
- Используем цикл for для повторения каждого item в cart
- Каждый item добавляем в список cashier с .append()
- Затем проверяем, какие элементы находятся в cashier с помощью print()
Как выполнить эти действия с list comprehension?
Что происходит здесь?
Те же самые действия, написанные другим способом. Сравним.
- Создание cashier выделено синим. Слева он занимает собственную строку, а справа создается одновременно с остальными элементами.
- Повторение cart выделено зеленым. item создается при запуске цикла for. Этот шаг аналогичен извлечению одного товара ( item ) из продуктовой корзины и передачи его кассиру.
- Обновление cashier с каждым item выделено красным. Единственное различие с левой стороны заключается в необходимости оператора .append() . Благодаря list comprehension справа оператор .append() можно не использовать.
Мы выполнили те же самые действия на одной строке кода, вместо трех. В случае, если проект Python занимает 1000 строк, его можно сократить до 300. Однако подобные сокращения можно выполнить не всегда. Это просто пример выполнения аналогичных действий с Pythonic-однострочником.
Что еще можно сделать с помощью list comprehensions в Python?
Рассмотрим еще несколько примеров.
cashier_3 работает только с четными числами. Как это изменить?
С помощью conditional, который выполняет действие при значении True и останавливается при False.
Как будет выглядеть код с list comprehension?
Что здесь происходит?
Этот пример аналогичен предыдущему, только conditional выделен желтым.
- Создание cashier_3 выделено синим.
- Повторение cart выделено зеленым. item создается при запуске цикла for.
- При передаче каждого item в cashier_3 , проверяется, совпадает ли он с conditional, выделенным желтым.
- Обновление cashier_3 с каждым item , выделенное красным, происходит до тех пор, пока элемент удовлетворяет требованиям conditional, выделенным желтым.
Числа больше 100 и нечетные числа
cashier_4 принимает только числа больше 100 и нечетные числа. Как это выполнить?
Пример с list comprehension.
Что дальше?
Это руководство затрагивает лишь основы list comprehensions в Python. Научившись работать с ними, вы поймете, насколько большое значение они имеют при написании краткого и эффективного Python кода.
Списковое включение (List comprehension) в Python

Списковое включение – это некий синтаксический сахар, позволяющий упростить генерацию последовательностей (списков, множеств, словарей, генераторов). Никто не заставляет его использовать в своем коде. Но если вы считаете себя (или стремитесь к этому) профессионалом, вы обязаны знать эту конструкцию.
Поначалу list comprehension может показаться сложным, но как только вы освоите эту возможность, то без проблем будете с ней работать.
1. Способы формирования списков
- при помощи циклов;
- при помощи функции map() ;
- при помощи list comprehension.
1.1. Использование цикла For
Наиболее удобным является цикл for (тем не менее, никто не мешает применять цикл while , если вам хочется лишней головной боли). Последовательность действий такова:
- Предсоздаем пустой список.
- Обходим список, в котором требуется произвести ряд преобразований, или осуществляем требуемое количество итераций цикла при помощи функцииrange().
- Добавляем в пустой список новые значения / элементы с помощью метода append() .
1.2. Использование функции map()
Этот способ переводит нас в область функционального программирования. Многие начинающие программисты боятся сталкиваться с этой темой. Понимать суть метода нужно, ведь вы можете встретить его в чужом скрипте.
Следует учесть, что map() возвращает не список, а итератор. Чтобы преобразовать его в список, нужно использовать функцию list() . Для получения итератора нужно задать функцию (которая применится к каждому элементу изначального списка) и сам список.
Читайте также
1.3. Использование генератора списка

List comprehension – элегантный способ создавать списки в стиле языка Python. Стоит один раз освоить – и вы всегда будете им пользоваться, где это уместно.
Общая структура выражения:
Здесь есть 3 элемента:
– операция подразумевает некие действия, которые вы собираетесь применить к каждому элементу списка;
– элемент списка – каждый отдельный объект списка;
– список – последовательность, элементы которой вы планируете подвергнуть операции (это не обязательно должен быть list , подойдет любой итерируемый объект).
Имеется начальный список цен на изделия. Сегодня на них дана скидка 10 %. Составим новый l ist с учетом удешевления стоимости.
2. Причины использовать list comprehension
Списковые включения считаются более «пайтонообразными», нежели циклы или функция map() для генерации списков. В других популярных языках программирования вы не встретите такой конструкции.
Их можно использовать не только в качестве «создателей» списков, но и для фильтрации данных. Зачастую (но не всегда – об этом будет сказано дальше) list comprehension проще понимать и читать в чужом коде (да и в своем, когда вы вернетесь к нему через некоторое время).
Вам не обязательно создавать пустой список, цикл, чтобы сформировать новую последовательность. Все это делается в одном единственном выражении.
3. Применение условий при генерировании списков
3.1. Условие в конце включения
3.2. Условие в начале включения
В отличие от предыдущего типа условий, здесь оно может дополняться вариантом else (но elif и тут невозможен).
Пример 7. Генерирование списка, в котором будут отмечены английские и неанглийские буквы
Представим задачу: нам дают строку, в которой могут присутствовать буквы любых алфавитов. И вот мы захотели составить новый список, где напротив каждой буквы будет отмечено, является ли она английской или нет.
Приступаем. Из модуля string импортирован объект ascii_letters , в котором содержатся только буквы английского алфавита:
4. Сложные списковые включения
Читайте также
5. Ограничения на применение списка включений
Хоть генераторы списков и выглядят красивыми, когда небольшие, они начинают становиться громоздкими по мере роста «мерности» и сложности.
Так как мы пишем код для людей, желательно стремиться к его максимальной читабельности. С приведенными в примере 8 и 9 ситуациями не следует частить. Никто вам не запрещает устроить хоть тройное вложение, но, поверьте, через несколько недель вы не сумеете разобраться в написанном, а что уж говорить о других людях.
Также, list comprehension даже теоретически не везде можно применить. Это касается вопроса замены циклов со множеством условий. Например, если бы задача с буквами разных алфавитов стояла иначе (напротив каждой буквы указать язык, к которому она принадлежит: русский, английский или греческий), мы бы никак не смогли воспользоваться генераторами списков.