Python

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

Изменение состояний, а не списка

Многие программисты, которые начинают с Python, используют ОС там, где он на самом деле не требуется. В следующем коде применение ОС  —  не лучшая идея, поскольку над самим списком не производится никаких действий.

vehicles = [ car, bike, truck ]
[ v.setLights(true) for v in vehicles ]

names = [ "A", "B", "C" ]
[ print(i) for n in names ]

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

Трансформация значений

Возможно, вы захотите преобразовать символы строки или просто добавить большое количество чисел. В любом из этих случаев, код не станет “питоническим”, если выбрать ОС, исходя только из того, что такой формат красиво выглядит:

total = 0
listOne = [1,2,3]
[total := total + x for x in listOne]

Оператор присваивания Python 3.8 := позволяет нам считать сумму элементов списка с помощью ОС, так зачем изобретать колесо, если язык предоставляет встроенную функцию sum()? ОС выше заменяется удивительно коротким фрагментом кода:

sum(listOne)

Точно так же, когда вы только разбиваете строку на символы или преобразуете её, не нужно использовать ОС:

str = "Fred"
chars = [x for x in str]

#Лучше так:
chars = list(str)

Огромная логика

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

list = [[1,2,3],[-1,-5,6]]

flatten = [item
           for sublist in list
           for item in sublist
           if item > 0]

#Использование циклов
flatten1 = []

for rows in list:
    for sublist in rows:
        if sublist > 0:
           flatten1.append(sublist)

Загрузка списка в память без необходимости 

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

sum([i * i for i in range(1000)])

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

sum(i* i for i in range(1000))

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

first = [x for x in list 
         if x.get("id")=="12"]

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

first = next((x for x in list if x.get("id")=="12"), None)

Сочетание функций itertools с генераторным выражением  — эффективный выход в отличие от ОС, который не поддерживает break и continue.

Злоупотребление охватом списка

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

myList = [('A', 1), ('B', 2), ('C', 3)]

result = [[ i for i, j in myList ],
       [ j for i, j in myList ]]

Python уже предоставляет встроенный инструмент, распаковывающий кортежи  —  это оператор *. Его можно применять при распаковке кортежа и передаче его в функцию zip для создания отдельных списков:

result = list(zip(*myList))

# [['A', 'B', 'C'], [1, 2, 3]]

Вывод

Охват списка в Python  —  мощный инструмент, но им легко злоупотребить, понизив тем самым эффективность и читаемость кода. Я надеюсь, что приведенные выше примеры неправильных подходов помогут вам лучше судить о том, когда не следует применять охват списка. Вот и всё на сегодня. Спасибо, что прочитали!

Читайте также:


Перевод статьи Anupam Chugh: 5 Wrong Use Cases Of Python List Comprehensions

Предыдущая статьяСоздание предметно-ориентированных микросервисов
Следующая статьяПортируем решатель судоку с Java на WebAssembly