Перейти к содержимому

Что такое списочное выражение в питон

  • автор:

Списочные выражения if else

Списочные выражения
Помогите пожалуйста! Списочные выражения Дополните приведенный код списочным выражением, чтобы.

Списочные выражения
Почему ошибка? ошибка вот ‘builtin_function_or_method’ object is not iterable Но я не знаю что это.

Как часто вы используете списочные выражения, я пришедший c c++, пока до конца не научился их использовать
Заканчиваю курс на платформе Степик и дошел до списочных выражений, никак не могу привыкнуть к их.

списочные ячейки
Всем доброго времени суток!) Посмотрите, пожалуйста, кому не сложно, правильно ли составлены.

Списочные структуры
В данной программе идет перечисление заданий с элементами. При работе выходит ошибка. uses crt;.

Что такое списочное выражение в питон

Скачай курс
в приложении

Перейти в приложение
Открыть мобильную версию сайта

© 2013 — 2023. Stepik

Наши условия использования и конфиденциальности

Get it on Google Play

Public user contributions licensed under cc-wiki license with attribution required

Списковые включения в Python мощнее, чем можно подумать

Правда, чаще всего их используют в форме, предусматривающей наличие единственного цикла for и, возможно, одного условия if . И это всё.

Потому что уже два уровня циклов требуют вчитывания, а что-то более сложное становится почти нечитаемым. Во всяком случае, на мой взгляд.

Всего голосов 12: ↑12 и ↓0 +12
Ответить Добавить в закладки Ещё

Плюсовики пишут на питоне =)
За такие штуки [y for y in (func(x) for x in values) if y] коллеги могут не просто косо посмотреть, но и что-нибудь в кофе подсыпать.

Всего голосов 12: ↑12 и ↓0 +12
Ответить Добавить в закладки Ещё
Показать предыдущий комментарий

`any((value := number) > 10 for number in numbers)`

а за такое использование моржового равенства даже в неприличном месте побьют

Комментарий пока не оценивали 0
Ответить Добавить в закладки Ещё

print([func(x) for x in values if func(x)]) # хреново print([y for y in (func(x) for x in values) if y]) # так себе print([y for x in values if (y := func(x))]) # получше print(list(filter(None, map(func, values)))) # вот так нормально

Всего голосов 9: ↑7 и ↓2 +5
Ответить Добавить в закладки Ещё

как же утомил Martin Heinz своим недалеким видением. ну серьезно. Уже писал про это и вот опять.

Да есть брейки в листах или однострочниках, есть. Но ему похоже не дано.

[n for n in range(10) if n != 4 or next([])], кстати чет не работает. видать пофиксили

Сапрессер ошибок есть:

supress(f(*args, **kwargs)) or handle(*args, **kwargs), хотя в его примере там обработчик ошибки а не значния.

Ну и листы, листы, кругом листы. Эк меня на листы триггерит.

Всего голосов 4: ↑4 и ↓0 +4
Ответить Добавить в закладки Ещё

Эх. Люди старались, match в других языках подсматривали придумывали:

for v in values: match v: case True: result.append('yes') case False: result.append('no') case _: result.append('unknown')

Хотя можно сделать коротко и без списковых включений:

a = for v in values: result.append(a[v])

Всего голосов 4: ↑4 и ↓0 +4
Ответить Добавить в закладки Ещё
Показать предыдущий комментарий

А case _: равнозначно None разве?

Комментарий пока не оценивали 0
Ответить Добавить в закладки Ещё
Показать предыдущий комментарий

Нет. Но у автора там тоже просто else.

Тут, скорее, вопросы к моему второму варианту. Который не совсем идентичен авторскому. Если возможные значения входных данных ограничены показанным набором — будет работать одинаково. Но если на вход придёт, например, 10 — будет ай-яй-яй.

Комментарий пока не оценивали 0
Ответить Добавить в закладки Ещё
Показать предыдущий комментарий

— result.append(a[v])
+ result.append(a.get(v, ‘unknown’))

Так будет работать эквивалентно авторскому =)

Всего голосов 2: ↑2 и ↓0 +2
Ответить Добавить в закладки Ещё

Лично мне очень нравится реализация перечислений БД в Tortoise ORM через генераторы.

Комментарий пока не оценивали 0
Ответить Добавить в закладки Ещё

имхо, «списочные выражения» как-то лучше звучит

Комментарий пока не оценивали 0
Ответить Добавить в закладки Ещё

«Однострочники Python: лаконичный и содержательный код [2022] Кристиан Майер»
Хорошая книга на эту тему.

Всего голосов 1: ↑1 и ↓0 +1
Ответить Добавить в закладки Ещё
Всего голосов 2: ↑0 и ↓2 -2
Ответить Добавить в закладки Ещё

Ну я так понимаю, что все примеры — это именно что «глядите, как можно», как в конце замечает сам автор.

Тогда нормально, забавно почитать. Главное, чтобы такое на работе не писали, а то на ревью вас всем отделом оттарабанят за тройные ифы в генераторах со всякими душными проверками какой-нибудь бизнес-логики.

Код должен не «занимать как можно меньше строк», а легко читаться, быть простым и понятным. Потому во всём надо знать меру и не перебарщивать

Списковые включения (list comprehension)

Списковые включения (list comprehension)

Списковые включения в Python являются краткими синтаксическими конструкциями. Их можно использовать для создания списков из других списков, применяя функции к каждому элементу в списке. В этом разделе объясняется и демонстрируется использование этих выражений.

Примеры

# списковое включение, выдаёт [2, 3, 4] [x + 1 for x in (1, 2, 3)] # генераторное выражение, выдаст 2, затем 3, затем 4 (x + 1 for x in (1, 2, 3)) # списковое включение с фильтром выдаёт [2] [x for x in (1, 2, 3) if x % 2 == 0] # списковое включение с тройкой [x + 1 if x % 2 == 0 else x for x in (1, 2, 3)] # списковое включение с тройкой и фильтрацией [x + 1 if x % 2 == 0 else x for x in range(-3,4) if x > 0] # комплект выражений, выдаёт  # словарь включений, выдаёт (python 2.7+ and 3.0+ only) # Вложенные циклы, дает [11, 21, 12, 22] [x + y for x in [1, 2] for y in [10, 20]] # Состояние проверено на 1-й петле [x + y for x in [1, 2, 3] if x > 2 for y in [3, 4, 5]] # Состояние проверено на 2-й петле [x + y for x in [1, 2, 3] for y in [3, 4, 5] if x > 2] # Условие проверено, если зацикленные числа нечётные [x for x in xrange(10) if x % 2 == 0] 

Замечания

Включения — это синтаксические конструкции, которые определяют структуры данных или выражения, уникальные для конкретного языка. Правильное использование включений переосмысливает их в понятные выражения. В качестве выражений их можно использовать:

  • в правой части присвоений
  • в качестве аргументов для вызова функций
  • в теле лямбда-функции
  • как отдельный оператор. (Например: [ print(x) для x в диапазоне (10)])

Примеры списковых включений

Списковые включения

Списковое включение создает новый list , применяя выражение к каждому элементу итерируемого. Наиболее простой формой является:

[ for in ]

Также есть необязательное условие if:

[ for in if ]

Каждый в подключается к если (необязательно) имеет значение true.Все результаты сразу возвращаются в новый список. Генератор включений вычисляет медленно, а списковые включения оценивают весь итератор — занимая память, пропорционально длине итератора.

Чтобы создать список квадратов целых чисел:

squares = [x * x for x in (1, 2, 3, 4)] squares #квадраты # [1, 4, 9, 16]

Выражение for устанавливает x для каждого значения по очереди из (1, 2, 3, 4) . Результат выражения x * x добавляется во внутренний список. Внутренний список присваивается переменным квадратам после завершения.

Помимо ускорения (как описано здесь), списковые включения примерно эквивалентны следующему циклу for:

squares = [] for x in (1, 2, 3, 4): squares.append(x * x) # [1, 4, 9, 16]

Выражение, применяемое к каждому элементу, может быть настолько сложным, насколько это необходимо:

# Получить список заглавных символов из строки [s.upper() for s in "Hello World"] # ['H', 'E', 'L', 'L', 'O', '', 'W', 'O', 'R', 'L', 'D'] # Убрать все запятые с конца строки в списке [w.strip(',') for w in ['these,', 'words,,', 'mostly', 'have,commas,']] # ['these', 'words', 'mostly', 'have,commas'] # Организовать буквы в словах в алфавитном порядке sentence = "Beautiful is better than ugly" ["".join(sorted(word, key = lambda x: x.lower())) for word in sentence.split()] # ['aBefiltuu', 'is', 'beertt', 'ahnt', 'gluy'] 

Условие Else

else можно использовать в списковых включениях, но нужно следить за синтаксисом. Условие if или else следует использовать перед циклом for , а не после:

# создать список символов из apple, replacing согласные на '*' # Ex - 'apple' --> ['a', '*', '*', '*' ,'e'] [x for x in 'apple' if x in 'aeiou' else '*'] # SyntaxError: invalid syntax # При использовании if / else используйте их перед циклом [x if x in 'aeiou' else '*' for x in 'apple'] # ['a', '*', '*', '*', 'e'] 

Обратите внимание, что здесь используется другая языковая конструкция, условное выражение, которое само по себе не является частью синтаксиса включения. Учитывая, что if после for…in является частью спискового включения и используется для фильтрации элементов из исходного кода.

Двойная итерация

Порядок двойной итерации [. for x in . for y in . ] является природным или контр-логичным. Эмпирическое правило это следовать циклу for :

def foo(i): return i, i + 0.5 for i in range(3): for x in foo(i): yield str(x) 
[str(x) for i in range(3) for x in foo(i) ] 

Это может быть сжат в одну строку, как [str(x) for i in range(3) for x in foo(i)]

Встроенная мутация и другие побочные эффекты

Прежде чем использовать списковые включения, нужно понять разницу между функциями, вызываемыми для их побочных эффектов (мутирующие или встроенные функции), которые обычно возвращают None , и функции , которые возвращают интересное значение.

Многие функции (особенно чистые функции) просто берут объект и возвращают какой-то объект. Встроенная функция изменяет существующий объект, это называется побочным эффектом. Другие примеры включают операции ввода и вывода, такие как print.

list.sort() сортирует список на месте (это означает , что он изменяет исходный список) и возвращает значение None .Следовательно, это не будет работать так, как со списковыми включениями:

[x.sort() for x in [[2, 1], [4, 3], [0, 1]]] # [None, None, None]

Вместо sorted() возвращает отсортированный list , а не сортировку на месте:

[sorted(x) for x in [[2, 1], [4, 3], [0, 1]]] # [[1, 2], [3, 4], [0, 1]]

Допускается использование включений для побочных эффектов, таких как ввод-вывод или встроенных функций. Тем не менее лучше использовать цикл for . Так это работает в Python 3:

[print(x) for x in (1, 2, 3)] 

Вместо этого используйте:

for x in (1, 2, 3): print(x)

В некоторых ситуациях функции побочных эффектов подходят для списковых включений. У random.randrange() есть побочный эффект изменения состояния генератора случайных чисел, но он также возвращает интересное значение. Кроме того, next() может вызываться на итераторе.

Следующий генератор случайных значений не является чистым, но имеет смысл, поскольку генератор случайных значений сбрасывается каждый раз, когда вычисляется выражение:

from random import randrange [randrange(1, 7) for _ in range(10)] # [2, 3, 2, 1, 1, 5, 2, 4, 3, 5]

Пробелы в списках

Более сложные списки могут быть очень длинными или становиться менее читабельными. В приведённых примерах это встречается не так часто, но можно разбить списковые включения на несколько строк следующим образом:

[ x for x in 'foo' if x not in 'bar' ] 

Избегайте повторяющихся и тяжёлых операций с использованием условий

Рассмотрим пример следующего спискового включения:

def f(x): import time time.sleep(.1) # Simulate expensive function return x**2 [f(x) for x in range(1000) if f(x) > 10] # [16, 25, 36, . ]

Это приводит к двум вызовам f(x) для 1000 значений x : один вызов для генерации значения, а другой для проверки условия if . Если f(x) является особенно тяжёлой операцией, это может существенно повлиять на производительность. Но хуже всего, если вызов f() имеет побочные эффекты, он может привести к неожиданным результатам.

Вместо этого вы должны оценивать тяжёлую операцию только один раз для каждого значения x , генерируя промежуточную итерацию (генераторное выражение) следующим образом:

[v for v in (f(x) for x in range(1000)) if v > 10] # [16, 25, 36, . ]

Или, используя эквивалентный map :

[v for v in map(f, range(1000)) if v > 10] # [16, 25, 36, . ] 

Другой способ, который может сделать код более читабельным — поместить частичный результат ( v в предыдущем примере) в итерацию (например, список или кортеж), а затем выполнить итерацию по нему. Поскольку v будет единственным элементом в итерации, в результате мы имеем ссылку на вывод нашей медленной функции, вычисляемой только один раз:

[v for x in range(1000) for v in [f(x)] if v > 10] # [16, 25, 36, . ]

Однако на практике логика кода может быть более сложной, и важно, чтобы код был читабельным. Как правило, лучше использовать отдельную функцию генератора вместо сложной однострочной:

def process_prime_numbers(iterable): for x in iterable: if is_prime(x): yield f(x) [x for x in process_prime_numbers(range(1000)) if x > 10] # [11, 13, 17, 19, . ]

Другой способ предотвратить многократное вычисление f(x) — это использовать декоратор @functools.lru_cache() (Python 3.2+) для f(x). Поскольку вывод f для ввода x уже был вычислен один раз, второй вызов функции исходного спискового включения будет таким же быстрым, как поиск по словарю. Этот подход использует запоминание для повышения эффективности, что сравнимо с использованием выражений генератора.

Скажем, вы должны сгладить список

l = [[1, 2, 3], [4, 5, 6], [7], [8, 9]]

Одним из методов может быть:

import functools # импорт библиотеки functools для функции reduce() functools.reduce(lambda x, y: x+y, l) # [1, 2, 3, 4, 5, 6, 7, 8, 9]

Ярлыки, основанные на + (включая подразумеваемое использование в сумме), по необходимости, O(L^2), где L — подсписки — как промежуточный результат продолжает увеличиваться, на каждом шаге новый объект списка промежуточных результатов резервируется, и все элементы в предыдущем промежуточном результате должны быть скопированы (а также несколько новых добавлены в конце). Поэтому для простоты скажем, что у вас есть L-подсписков с I элементов в каждом: первые I элементы копируются L-1 раз, вторые I-элементы L-2 раза и т.д .; общее количество копий равно I, умноженному на сумму x для x от 1 до L, т.е. I*(L**2)/2.

Списковое включение только генерирует список один раз, и копирует каждый элемент также ровно один раз.

Изменение типов в списке

Пример

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

# Преобразовать список строк в целые числа. items = ["1","2","3","4"] [int(item) for item in items] # [1, 2, 3, 4] # Преобразовать список строк в плавающий. items = ['1','2','3','4'] list(map(float, items)) # [1.0, 2.0, 3.0, 4.0] 

Включения с участием кортежей

Пример

Условие for списковых включений может указывать более одной переменной:

[x + y for x, y in [(1, 2), (3, 4), (5, 6)]] # [3, 7, 11] [x + y for x, y in zip([1, 3, 5], [2, 4, 6])] # [3, 7, 11]

Это как обычный цикл for:

for x, y in [(1,2), (3,4), (5,6)]: print(x+y) # 3 # 7 # 11

Нужно обратить внимание, что если начинающее включение является кортежем, его необходимо заключить в скобки:

[x, y for x, y in [(1, 2), (3, 4), (5, 6)]] # SyntaxError: invalid syntax [(x, y) for x, y in [(1, 2), (3, 4), (5, 6)]] # [(1, 2), (3, 4), (5, 6)]

Подсчет вхождений с использованием включений

Пример

Когда мы хотим подсчитать количество элементов в итерации, которые удовлетворяют некоторому условию, мы можем использовать включение для создания идиоматического синтаксиса:

# Посчитать числа в `range(1000)` которые чётные или содержат цифру `9`: print(sum( 1 for x in range(1000) if x % 2 == 0 and '9' in str(x) )) # 95

Основная концепция такова:

  1. Перебирать элементы в диапазоне (1000).
  2. Объедините все необходимые if условия.
  3. Используйте 1 в качестве выражения, чтобы вернуть 1 для каждого элемента, который соответствует условиям.
  4. Суммируйте все 1 , чтобы определить количество предметов, которые соответствуют условиям.

Примечание: здесь мы не собираем 1 в списке (обратите внимание на отсутствие квадратных скобок), но мы передаём их непосредственно функции суммирования, которая их суммирует. Это генератор выражений, который похож на включения.

Словарь включений

Пример

Словарь включений аналогичен списковым включениям, за исключением того, что он создаёт объект словаря вместо списка.

это просто еще один способ написания:

dict((x, x * x) for x in (1, 2, 3, 4)) #

Как и в случае со списком, мы можем использовать условный оператор внутри словаря включения, чтобы получить только элементы словаря, удовлетворяющие заданному критерию.

Или переписать с помощью генераторного выражения.

dict((name, len(name)) for name in('Stack', 'Overflow', 'Exchange') if len(name) > 6) #

Начиная со словаря и используя словарь в качестве фильтра пары ключ-значение

initial_dict =  #

Переключение ключа и значения словаря (инвертировать словарь)

my_dict =

если вы хотели поменять местами ключи и значения, вы можете использовать несколько подходов в зависимости от вашего стиля кодирования:

swapped = swapped = dict((v, k) for k, v in my_dict.items()) swapped = dict(zip(my_dict.values(), my_dict)) swapped = dict(zip(my_dict.values(), my_dict.keys())) swapped = dict(map(reversed, my_dict.items())) print(swapped) #

Объединение словарей

Объедините словари и при необходимости переопределите старые значения с помощью вложенного словаря включений.

dict1 = dict2 =  #

Примечание: словарь включений был добавлен в Python 3.0 и перенесён в версию 2.7+, в отличие от списочных включений, которые были добавлены в 2.0. Версии

Генераторные выражения

Пример

Генераторное выражение очень похоже на списки. Основное отличие состоит в том, что оно не создаёт полный набор результатов сразу; он создаёт объект генератора, который затем может быть повторён.

Например, посмотрите различия в коде:

# списковое включение [x**2 for x in range(10)] # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

Примечание: В Python 3, range просто возвращает генератор. Для получения дополнительной информации см Различия между функциями дальности и xrange например.

Сценарии использования

Генераторные выражения вычисляются лениво, что означает, что они генерируют и возвращают каждое значение только тогда, когда генератор повторяется. Это может пригодиться при переборе больших наборов данных, без создания дубликатов набора данных в памяти:

for square in (x**2 for x in range(1000000)): #сделает что-нибудь 

Другим распространенным вариантом использования является недопущение итерации по всей итерации когда не требуется. В этом примере элемент извлекается из удаленного API с каждой итерацией get_objects() . Тысячи объектов могут существовать, должны быть найдены один за другим, и нам нужно только знать, существует ли объект, который соответствует шаблону. Используйте генераторное выражение, когда мы видим похожую задачу

def get_objects(): # Получает объект из API один за одним while True: yield get_next_item() def object_matches_pattern(obj): # выполнит потенциально сложный расчет return matches_pattern def right_item_exists(): items = (object_matched_pattern(each) for each in get_objects()) for item in items: if item.is_the_right_one: return True return False 

Набор включений

Пример

Набор включений аналогичен списку включений и словарю включений, но он создаёт набор, представляющий собой неупорядоченную коллекцию уникальных элементов.

# Набор, содержащий каждое значение в диапазоне (5): # # Набор чётных чисел от 1 до 10: # # Уникальные буквенные символы в текстовой строке: text = "When in the Course of human events it. " #

Имейте в виду, что наборы неупорядочены. Это значит, что порядок результатов в наборе может отличаться от того, который представлен в приведённых выше примерах.

Примечание: Набор включений доступен с версии Python 2.7+, в отличие от списка включений, которые были добавлены в 2.0. В Python 2.2 — Python 2.6 функция set() может использоваться с выражением генератора для получения того же результата:

set(x for x in range(5)) #

Условные списки

Учитывая список понимание вы можете добавить один или несколько , if условия для фильтрации значений.

[ for in if ] 

Для каждого в если имеет значение True , добавить (обычно функция ) в возвращаемом списке.

Например, это можно использовать для извлечения только четных чисел из последовательности целых чисел:

[x for x in range(10) if x % 2 == 0] # [0, 2, 4, 6, 8]

Приведенный выше код эквивалентен:

even_numbers = [] for x in range(10): if x % 2 == 0: even_numbers.append(x) print(even_numbers) # [0, 2, 4, 6, 8]

Кроме того , усвоение условного списка вида [e for x in y if c] , где e и c являются выражениями в терминах x ) эквивалентно list(filter(lambda x: c, map(lambda x: e, y)))

Несмотря на предоставление того же результата, обратите внимание на тот факт, что первый пример почти в 2 раза быстрее, чем второй. Для тех , кому любопытно, это хорошее объяснение причин почему.

Обратите внимание , что это совершенно отличается от . if . else . условного выражения (иногда известное как трехкомпонентное выражение ) , которые вы можете использовать для часть списка понимания. Рассмотрим следующий пример:

[x if x % 2 == 0 else None for x in range(10)] # [0, None, 2, None, 4, None, 6, None, 8, None]

Здесь условное выражение — не фильтр, а оператор, определяющий значение, которое будет использоваться для элементов списка:

 if else

Это становится более очевидным, если вы объедините его с другими операторами:

[2 * (x if x % 2 == 0 else -1) + 1 for x in range(10)] # [1, -1, 5, -1, 9, -1, 13, -1, 17, -1]

Приведенный выше код эквивалентен:

numbers = [] for x in range(10): if x % 2 == 0: temp = x else: temp = -1 numbers.append(2 * temp + 1) print(numbers) # [1, -1, 5, -1, 9, -1, 13, -1, 17, -1]

Можно комбинировать тройные выражения и if условия. Тернарный оператор работает с отфильтрованным результатом:

[x if x > 2 else '*' for x in range(10) if x % 2 == 0] # ['*', '*', 4, 6, 8] 

То же самое не могло быть достигнуто только одним троичным оператором:

[x if (x > 2 and x % 2 == 0) else '*' for x in range(10)] # Out:['*', '*', '*', '*', 4, '*', 6, '*', 8, '*'] 

Смотрите также: фильтры , которые часто обеспечивают достаточную альтернативу условных списковые.

Перечень списков с помощью вложенных циклов

Списки могут использовать вложенный for .Вы можете закодировать любое количество вложенных циклов для внутри списка понимания, и каждый for цикла может иметь дополнительный связанный , if тест. При этом порядок следования for построений такой же порядок , как при написании серии вложенных for заявлений. Общая структура списочных представлений выглядит следующим образом:

[ expression for target1 in iterable1 [if condition1] for target2 in iterable2 [if condition2]. for targetN in iterableN [if conditionN] ] 

Например, следующий код уплощение списка списков с использованием нескольких for операторов:

data = [[1, 2], [3, 4], [5, 6]] output = [] for each_list in data: for element in each_list: output.append(element) print(output) # [1, 2, 3, 4, 5, 6]

Можно эквивалентно записать в виде списка с кратной for конструкцией:

data = [[1, 2], [3, 4], [5, 6]] output = [element for each_list in data for element in each_list] print(output) # Out: [1, 2, 3, 4, 5, 6] 

Как в расширенной форме, так и в понимании списка, внешний цикл (первый для оператора) идет первым.

В дополнение к более компактному вложенному пониманию также значительно быстрее.

data = [[1,2],[3,4],[5,6]] def f(): output=[] for each_list in data: for element in each_list: output.append(element) return output timeit f() # 529 ns ± 4.75 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each) timeit [inner for outer in data for inner in outer] # 360 ns ± 14.2 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each) 

Накладные расходы на вызов функции выше примерно 170ns.

Встроенный , if ы вложены подобным образом , и может происходить в любом положении после первого for :

data = [[1], [2, 3], [4, 5]] output = [element for each_list in data if len(each_list) == 2 for element in each_list if element != 5] print(output) # [2, 3, 4] 

Ради удобства чтения, однако, вы должны рассмотреть возможность использования традиционного для петель. Это особенно верно, когда вложение глубиной более 2-х уровней и / или логика понимания слишком сложна. многократное понимание списка вложенных циклов может быть подвержено ошибкам или дает неожиданный результат.

Фильтр рефакторинга и map для отображения списка

В filter или map функция часто должна быть заменена списком. Гвидо ван Россум описывает это хорошо в открытом письме в 2005 году :

Следующие строки коды считаются «не рабочими» и будут вызывать ошибки.

# четные числа < 10 filter(lambda x: x % 2 == 0, range(10)) # # чтобы получить итоговый список ее надо преобразовать list(filter(lambda x: x % 2 == 0, range(10))) #[0, 2, 4, 6, 8] # умножение каждого числа на 2 map(lambda x: 2*x, range(10)) # чтобы вызвать ее надо преобразовать ее в список # сумма всех элементов в списке functools.reduce(lambda x,y: x+y, range(10)) 

Принимая то , что мы узнали из предыдущей цитаты, мы можем сломать эти filter и map выражения в эквивалентных им списковые; также удаление лямбда - функции от каждого - сделать код более читаемым в этом процессе.

# Filter: # P(x) = x % 2 == 0 # S = range(10) [x for x in range(10) if x % 2 == 0] # [0, 2, 4, 6, 8] # Map # F(x) = 2*x # S = range(10) [2*x for x in range(10)] # [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

Читаемость становится еще более очевидной при работе с цепными функциями. Из-за читабельности, результаты одного map или функции фильтра должны быть переданы в качестве результата следующей; в простых случаях их можно заменить единый список. Кроме того, мы можем легко понять каков результат нашего процесса, где существует большая когнитивная нагрузка при рассуждениях о цепочечном процессе map и filter .

# Map & Filter filtered = filter(lambda x: x % 2 == 0, range(10)) results = map(lambda x: 2*x, filtered) print(list(results)) # [0, 4, 8, 12, 16] # List comprehension results = [2*x for x in range(10) if x % 2 == 0] print(results) # [0, 4, 8, 12, 16]

Рефакторинг - краткий справочник

map

map(F, S) == [F(x) for x in S] 

Фильтр

filter(P, S) == [x for x in S if P(x)] 

где F и P являются функциями , которые соответственно преобразуют входные значения и возвращают bool

Списковые включения с участием кортежей

for пункта в список понимания можно указать более одной переменные:

[x + y for x, y in [(1, 2), (3, 4), (5, 6)]] # [3, 7, 11] [x + y for x, y in zip([1, 3, 5], [2, 4, 6])] # [3, 7, 11] 

Это так же , как регулярные for петель:

for x, y in [(1,2), (3,4), (5,6)]: print(x+y) # 3 # 7 # 11

Однако обратите внимание, что если выражение, начинающее списковое включение, является кортежем, его необходимо заключить в скобки:

[x, y for x, y in [(1, 2), (3, 4), (5, 6)]] # SyntaxError: invalid syntax [(x, y) for x, y in [(1, 2), (3, 4), (5, 6)]] # [(1, 2), (3, 4), (5, 6)]

Подсчет вхождений

Когда мы хотим подсчитать количество элементов в итерируемом элементе, которые удовлетворяют некоторому условию, мы можем использовать списковое включение для создания идиоматического синтаксиса:

# Подсчет числе в списке от 1 до 1000 (`range(1000)`), которые четные и содержат цифру 9 `9`: print(sum( 1 for x in range(1000) if x % 2 == 0 and '9' in str(x) )) # 95

Основная концепция может быть обобщена как:

  1. Итерации над элементами в range(1000) .
  2. Сцепить все необходимое , при выполнении условия if .
  3. Используйте 1 в качестве выражения для возврата 1 для каждого элемента, который соответствует условиям.
  4. Суммируем все 1 , чтобы определить количество элементов , которые удовлетворяют условиям.

Примечание: Здесь мы не собираем все 1 в одном списке (обратите внимание на отсутствие квадратных скобок), но мы считаем их непосредственно через функцию sum . Это называется выражение генератора, который похож на списковое включение.

Изменение типов в списке

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

# конвертируем список строк в целые числа. items = ["1","2","3","4"] [int(item) for item in items] # [1, 2, 3, 4] # Конвертируем список строк в числа с плавающей точкой. items = ["1","2","3","4"] list(map(float, items)) # [1.0, 2.0, 3.0, 4.0] 

Понимание вложенного списка

Включение вложенного списка, в отличие от включения списка с вложенными циклами, являются включение списка в пределах включения списка. Начальным выражением может быть любое произвольное выражение, включая другое включение.

#Списковое включение с вложенным циклом [x + y for x in [1, 2, 3] for y in [3, 4, 5]] #Out: [4, 5, 6, 5, 6, 7, 6, 7, 8] #Вложенное списковое включение [[x + y for x in [1, 2, 3]] for y in [3, 4, 5]] #Out: [[4, 5, 6], [5, 6, 7], [6, 7, 8]] 

Вложенный пример эквивалентен

l = [] for y in [3, 4, 5]: temp = [] for x in [1, 2, 3]: temp.append(x + y) l.append(temp)

Один пример, где вложенное списковое включение может быть использовано для транспонирования матрицы.

matrix = [[1,2,3], [4,5,6], [7,8,9]] [[row[i] for row in matrix] for i in range(len(matrix))] # [[1, 4, 7], [2, 5, 8], [3, 6, 9]]

Как и вложенные for петель, есть не предел того , как глубоко постижения могут быть вложенными.

[[[i + j + k for k in 'cd'] for j in 'ab'] for i in '12'] # [[['1ac', '1ad'], ['1bc', '1bd']], [['2ac', '2ad'], ['2bc', '2bd']]] 

Итерация двух или более списков одновременно в пределах понимания списка

Для перебора более двух списков одновременно в списковым включении, можно использовать zip() , как:

list_1 = [1, 2, 3 , 4] list_2 = ['a', 'b', 'c', 'd'] list_3 = ['6', '7', '8', '9'] # 2 списка [(i, j) for i, j in zip(list_1, list_2)] # [(1, 'a'), (2, 'b'), (3, 'c'), (4, 'd')] # 3 списка [(i, j, k) for i, j, k in zip(list_1, list_2, list_3)] # [(1, 'a', '6'), (2, 'b', '7'), (3, 'c', '8'), (4, 'd', '9')] # итд

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *