eFusion 30 декабря 2019

5 полезных фич Python, о которых знают не все

Python – один из самых популярных и мощных ЯП, скрывающих массу полезностей и фич. Пять из них мы осветили в статье.
2
5805

Даже если ты программист, перешедший с других языков, таких как C, в программирование на Python с более высоким уровнем абстракции – не стоит пугаться и отступать перед “не таким” кодом. Погнали!

List comprehensions – компактный код

Многие назвали бы lambda, map и filter "трюками" Python, которым должен научиться каждый новичок. Принято считать, что эти функции большую часть времени, не особенно полезны, поскольку им не хватает гибкости.

Лямбда – это метод составления функции в одну строку для одноразового использования. Если он вызывается несколько раз, страдает производительность. С другой стороны, 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]
    

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

        # Syntax of list comprehension
[ 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]
    

Манипуляции со списками – циклические списки

Python поддерживает отрицательную индексацию, где aList[-1] == aList[len(aList)-1]. Исходя из этого, можно получить второй последний элемент в списке – aList[-2] и так далее.

Также можно нарезать списки с помощью записи aList[start:end: step], где начальный элемент указан, а конечный – нет. Поэтому вызов aList[2:5] вернет [2, 3, 4], а вызвав aList[:: -1], ты сможешь переставить элементы в списке в обратном порядке – очень элегантная техника.

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

        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
    

zip, enumerate и for-loops

Функция zip создает итератор, который агрегирует элементы из нескольких списков. Он позволяет выполнять параллельный обход списков в цикле for и параллельную сортировку. Обратное действие (unzip) совершается с помощью звездочки.

        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} is {eng} in English and {esp} in Spanish.')
# 0 is zero in English and cero in Spanish.
# 1 is one in English and uno in Spanish.
# 2 is two in English and dos in Spanish.
    
        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 = ['A', 'B', 'C', 'D', 'E', 'F']
lowerCase = ['a', 'b', 'c', 'd', 'e', 'f']
for i, (upper, lower) in enumerate(zip(upperCase, lowerCase), 1):
    print(f'{i}: {upper} and {lower}.')
# 1: A and a.
# 2: B and b.
# 3: C and c.
# 4: D and d.
# 5: E and e.
# 6: F and f.
    

Генератор – эффективность использования памяти

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

Они часто используются при чтении больших файлов или создании бесконечной последовательности при помощи ключевого слова yield.

        def gen(n):    # an infinite sequence generator that generates integers >= n
    while True:
        yield n
        n += 1
        
G = gen(3)     # starts at 3
print(next(G)) # 3
print(next(G)) # 4
print(next(G)) # 5
print(next(G)) # 6
    

Виртуальная среда – изоляция

Самая интересная и увлекательная штука из подборки.

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

        conda create -n venv pip python=3.7  # select python version
source activate venv
...
source deactivate
    

Поэтому крайне важно создать отдельные автономные виртуальные среды venv для каждого приложения, что и можно сделать с помощью pip или conda.

А какие фичи в Python любишь ты?

Источники

РУБРИКИ В СТАТЬЕ

МЕРОПРИЯТИЯ

Комментарии 2

ВАКАНСИИ

IOS developer
Москва, от 150000 RUB до 220000 RUB
Разработчик Java (микросервисы)
по итогам собеседования
Middle/Senior Java Developers
по итогам собеседования

ЛУЧШИЕ СТАТЬИ ПО ТЕМЕ

BUG