Фичи поинтереснее, чем lambda, map и filter.
Python, несомненно, самый быстрорастущий язык программирования этого десятилетия — он очень мощный. Я писал на нем множество проектов — от интерактивных карт до блокчейна. В Python настолько много фич, что новичку порой тяжело освоить все сразу.
Python — язык с высоким уровнем абстракции. Это совершенно новый опыт — даже для тех программистов, которые переходят с Си или MATLAB. Я очень жалею, что не узнал о некоторых фичах Python раньше. Именно поэтому я выделил пять самых интересных из них.
1. Генератор списков — залог компактного кода
Много кто выделил бы лямбда-функции, map, filter и назвал их полезными «хитростями», о которых должен знать каждый новичок. Хоть я и уверен, что знать эти функции необходимо, но я бы не сказал, что они полезны — им не хватает гибкости.
Lambda
— способ написать однострочную функцию для одноразового использования. Чрезмерное использование функций отрицательно сказывается на производительности. Но существует map
: она применяет функцию ко всем элементам итерируемого объекта. Filter
же применяет функцию только к тем элементам , которые соответствуют условиям, определенным пользователем.
add_func = lambda z: z ** 2 is_odd = lambda z: z%2 == 1 multiply = lambda x,y: x*y aList = list(range(10)) print(aList) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Генератор списков — лаконичный и гибкий способ создания списков из списков с помощью выражений и условий. Синтаксис простой — квадратные скобки. Внутри — выражение или функция. Применяются они к каждому элементу списка, который удовлетворяет заранее заданным условиям. Для обработки вложенных списков существуют вложенные генераторы — они гораздо удобнее, чем map и filter.
# Синтаксис генератора списков [ expression(x) for x in aList if optional_condition(x) ]
print(list(map(add_func, aList))) print([x ** 2 for x in aList]) # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] print(list(filter(is_odd, aList))) print([x for x in aList if x%2 == 1]) # [1, 3, 5, 7, 9] # [1, 3, 5, 7, 9]
2. Грамотная манипуляция со списками — круговые списки
Python позволяет использовать отрицательную индексацию — aList[-1] == aList[len(aList)-1]
. То есть, мы можем получить второй с конца элемент с помощью конструкции aList[-2]
.
Также мы можем использовать оператор среза с помощью синтаксиса aList[начало:конец:шаг]
. То есть, вызов aList[2:5]
возвращает [2, 3, 4]
. Мы можем перевернуть список, вызвав aList[::-1]
. Мне кажется, это очень элегантно.
Список может быть разделен на отдельные элементы или набор элементов и подсписки с помощью оператора *.
aList = range(10) a, b, c, d = aList[0:4] print(f'a = {a}, b = {b}, c = {c}, d = {d}') # a = 0, b = 1, c = 2, d = 3 a, *b, c, d = aList print(f'a = {a}, b = {b}, c = {c}, d = {d}') # a = 0, b = [1, 2, 3, 4, 5, 6, 7], c = 8, d = 9
3. Zipping и enumerate в циклах for
Функция zip
создает итератор, который объединяет элементы из нескольких списков. Он позволяет параллельно просмотреть несколько итерируемых объектов в цикле for и и выполнить их сортировку. Распаковка осуществляется с помощью оператора *.
numList = [0, 1, 2] engList = ['zero', 'one', 'two'] espList = ['cero', 'uno', 'dos'] print(list(zip(numList, engList, espList))) # [(0, 'zero', 'cero'), (1, 'one', 'uno'), (2, 'two', 'dos')] for num, eng, esp in zip(numList, engList, espList): print(f'{num} на английском {eng} и {esp} — на испанском.') # 0 на английском zero и cero — на испанском. # 1 на английском one и uno — на испанском. # 2 на английском two и dos — на испанском.
Eng = list(zip(engList, espList, numList)) Eng.sort() # sort by engList a, b, c = zip(*Eng) print(a) print(b) print(c) # ('one', 'two', 'zero') # ('uno', 'dos', 'cero') # (1, 2, 0)
Поначалу Enumerate
кажется довольно сложной, но во многих сценариях она может оказаться очень полезной. У этой функции есть автоматический счетчик — порой используется в циклах for. То есть, благодаря этой функции пропадает нужда в объявлении и инициализации переменных-счетчиков вроде counter = 0
и counter += 1
. Enumerate и zip — два мощнейших инструмента, помогающих при создании циклов for.
upperCase = ['А', 'Б', 'В', 'Г', 'Д', 'Е'] lowerCase = ['а', 'б', 'в', 'г', 'д', 'е'] for i, (upper, lower) in enumerate(zip(upperCase, lowerCase), 1): print(f'{i}: {upper} и {lower}.') # 1: А и а. # 2: Б и б. # 3: В и в. # 4: Г и г. # 5: Д и д. # 6: Е и е.
4. Эффективное управление памятью — генераторы
Генераторы используются в случаях, когда необходимо вычислить большой набор данных, но нет возможности выделить память для всех результатов одновременно. Другими словами, они генерируют значения динамически и не хранят в памяти предыдущие значения. Следовательно, обход этой последовательности можно провести лишь раз.
Полезны генераторы при работе с большими данными или генерации бесконечных последовательностей с помощью ключевого слова yield
. Я очень часто пользуюсь генераторами при работе с моими проектами по data science.
5. Изоляция — виртуальные окружения
Если бы вы могли вспомнить из этой статьи только один абзац, то им должен стать этот.
Приложение Python — сложная зависимость разных библиотек. И ведь все они от разных разработчиков. Приложения создаются с помощью определенных настроек определенных библиотек. То есть, результаты одной версии библиотеки не могут воспроизвести результаты другой. Не существует унифицированной версии библиотеки, которая подойдет под любой проект.
conda create -n venv pip python=3.7 # select python version source activate venv ... source deactivate
Следовательно, для каждого приложения чрезвычайно важно создавать отдельные автономные виртуальные окружения venv
. Делается это с помощью pip
или conda
.