Подборка трюков и другой интересной информации в Python третьей версии, которая поможет вам при меньших усилиях писать более качественный программный код.
Python – язык программирования с ясным синтаксисом, и многие удобные вещи в силу простоты часто не задерживаются в памяти. При этом самые краткие и красивые решения обычно оказываются наиболее быстрыми. В представленной ниже подборке из 15 трюков в Python вы наверняка встретите приемы, знаний о которых не хватало в определенный момент в вашей практике.
1. Объединение списков без цикла
Как бы вы решили задачу объединения списков разной длины без обхода элементов цикла? Вот как это можно сделать с помощью стандартной функции sum:
L = [[1, 2, 3], [4, 5], [6], [7, 8, 9]]
print(sum(L, []))
[1, 2, 3, 4, 5, 6, 7, 8, 9]
Пусть и менее краткий, но более эффективный способ – применение модуля itertools:
import itertools
L = [[1, 2, 3], [4, 5], [6], [7, 8, 9]]
print(list(itertools.chain.from_iterable(L)))
Заметим, что при работе с последовательностями многие полезные решения находятся в модулях стандартной библиотеки collections (контейнерные структуры данных) и itertools (операции над последовательностями). Внимательное прочтение документации модулей освободит вас от многих часов придумывания собственных «велосипедов».
2. Обмен значениями при помощи кортежей
Один из популярных трюков в Python – обмен значениями без создания временной переменной. Способ применим для любого числа переменных.
a, b = 1, 2
print(a, b)
a, b = b, a
print(a, b)
1 2
2 1
В правой части инструкции присваивания последовательностей допускается указывать любые итерируемые объекты.
Главное, чтобы число элементов слева равнялось числу элементов справа. Такое присваивание применяется и для сложных вложенных конструкций:
for ((a, b), c) in [((1, 2), 3), ((4, 5), 6)]:
print(a, b, c)
1 2 3
4 5 6
3. Распаковывание последовательностей при неизвестном числе элементов
Для указанного в подзаголовке случая в Python 3 есть оператор звездочки – расширенная операция распаковывания последовательности.
Переменной со звездочкой присваивается часть списка, содержащая все неприсвоенные элементы, соответствующие этой позиции:
seq = [1, 2, 3, 4]
*a, b, c = seq
print(a, b, c)
a, *b, c = seq
print(a, b, c)
a, b, *c = seq
print(a, b, c)
a, b, c, *d = seq
print(a, b, c, d)
a, b, c, d, *e = seq
print(a, b, c, d, e)
[1, 2] 3 4
1 [2, 3] 4
1 2 [3, 4]
1 2 3 [4]
1 2 3 4 []
Подобные операции можно осуществить и при помощи срезов, но такой код выглядит естественнее.
Расширенную операцию распаковывания используют и в циклах, когда длина вложенных последовательностей варьируется:
for (a, *b, c) in [(1, 2, 3), (4, 5, 6, 7)]:
print(a, b, c)
1 [2] 3
4 [5, 6] 7
4. Объединение строк
В программном коде нередко приходится сталкиваться с конкатенацией строк при помощи знака сложения. Создание строки из списка нескольких подстрок удобнее осуществить при помощи строкового метода join:
a = [“Python”, “-“, “прекрасный”, “язык.”]
print(” “.join(a))
Пример посложнее с методом join – конвертирование списка чисел в строку:
numbers = [1, 2, 3, 4, 5]
print(', '.join(map(str, numbers)))
1, 2, 3, 4, 5
5. Проверка на анаграммность
Проверить, являются ли строки анаграммами (например, в результате случайной перестановки букв) поможет класс Counter модуля collections:
from collections import Counter
str1 = 'proglib'
str2 = 'prgolib'
print(Counter(str1) == Counter(str2))
True
6. Транспонирование двумерного массива данных
Чтобы поменять местами строки и столбцы матрицы, созданной с помощью встроенных типов данных, воспользуйтесь функцией zip:
original = [('a', 'b'), ('c', 'd'), ('e', 'f')]
transposed = zip(*original)
print(list(transposed))
[('a', 'c', 'e'), ('b', 'd', 'f')]
Если вы регулярно сталкиваетесь с подобными задачами, вместо таких трюков в Python принято использовать библиотеку NumPy.
7. Удаление дубликатов в списке
Среди регулярно используемых трюков в Python – преобразование списка во множество и обратно в список для удаления повторяющихся элементов списка:
items = [2, 2, 3, 3, 1]
print(list(set(items)))
[1, 2, 3]
Но множества – это неупорядоченные последовательности. Часто стоит задача сохранить порядок следования элементов. Для этого удобно воспользоваться типом данных OrderedDict из модуля collections:
items = [2, 2, 3, 3, 1]
from collections import OrderedDict
print(list(OrderedDict.fromkeys(items).keys()))
[2, 3, 1]
8. Назначение переменных и функций по условию
Иногда элементы if настолько просты, что кажется излишним тратить на них строки. В этом случае имеет смысл применить тернарный оператор if/else:
A = Y if X else Z
Интерпретатор выполняет выражение Y, если объект X – истина, и Z, если X – ложь. Не злоупотребляйте этим выражением, если X, Y, Z имеют сложную форму записи.
Тернарный оператор можно использовать не только для переменных, но и для функций:
def product(a, b):
return a * b
def summarize(a, b):
return a + b
c = True
print((product if c else summarize)(3, 4))
12
9. Присвоение первого непустого значения из ряда
Следующая инструкция
X = A or B or C or None
присвоит переменной X первый непустой (имеющий истинное значение) объект из множества объектов A, B и С или None, если все предыдущие объекты окажутся пустыми. В простейшем виде эту особенность используют для задания значения по умолчанию:
X = A or default
Аналогичным образом логический оператор and можно применять для нахождения первого ложного значения.
10. Вывод значения по умолчанию для отсутствующего ключа словаря
Обращение к несуществующему ключу словаря вызывает исключение. Избежать этого можно, вызывая метод get. В указанном случае метод выдает None (по умолчанию) или заданное значение аргумента.
d = {'a':1, 'b':2}
print(d.get('c'))
print(d.get('c', 3))
None
3
При создании собственного типа данных на основе словарей обратите внимание на метод __missing__ для возвращения аргумента при отсутствии ключа:
class MyDict(dict):
def __missing__(self, key):
return key
D = MyDict(a=1, b=2)
print(D)
print(D['a'])
print(D['c'])
{'a': 1, 'b': 2}
1
c
11. Вывод при помощи print
Часто указывается, что основное различие Python 2-й и 3-й версий – это скобки после инструкции print. Это же означает, что инструкция print стала функцией, а значит, скобки могут включать какие-то дополнительные аргументы.
Так и есть. В print имеются следующие аргументы:
- строка sep (по умолчанию один пробел), вставляемая между объектами при выводе;
- строка end (по умолчанию \n), добавляемая в конец выводимого текста;
- file (по умолчанию sys.stdout) – любой объект, поддерживающий метод файлов write(string), то есть стандартный поток, файл и др.
Например, если нам не нужно объединять подстроки, а лишь напечатать суммарную строку:
for part in ["prog", "lib", ".io", "\n"]:
print(part, end='')
proglib.io
Тот же подход можно практиковать для чтения файлов:
for line in open(‘script.py’):
print(line, end=”)
Присвоение аргументу end пустой строки приводит к тому, что строки файла не перемежаются пустыми строками. Иначе при чтении строк файла и использовании end по умолчанию символ окончания строки \n повторялся бы два раза.
12. Нумерованные списки
Задача нумерации элементов последовательности настолько распространена, что в Python есть соответствующая встроенная функция enumerate:
for i, item in enumerate(['a', 'b', 'c']):
print(i, item)
0 a
1 b
2 c
Для тех, кто уже знаком с enumerate, может оказаться новостью, что у функции есть второй аргумент, задающий начальное число:
for i, item in enumerate(['a', 'b', 'c'], 1):
print(i, item)
1 a
2 b
3 c
13. Сортировка словаря по значениям
Распространена практика использования словарей в качестве таблиц для хранения данных. Сортировка данных словаря по значениям ключей, а не самим ключам, нередко ставит в тупик. Задача решается довольно просто при помощи соответствующего аргумента функции сортировки:
d = {'яблоки':40, 'апельсины':80, 'бананы':70}
print(sorted(d, key=d.get))
['яблоки', 'бананы', 'апельсины']
14. Генераторы словарей и множеств
Вы, конечно, пользовались генераторами списков. Но знаете ли вы о генераторах множеств и словарей?
S = {i**2 for i in range(10)}
D = {i: i**2 for i in range(10)}
print(S)
print(D)
{0, 1, 64, 4, 36, 9, 16, 49, 81, 25}
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49, 8: 64, 9: 81}
В случае словарей отличие только в парах ключ-значение. Такие генераторы удобны для начальной инициализации значений последовательностей.
15. Нахождение наиболее часто повторяющихся элементов списка
Найти самый часто повторяющийся элемент можно с помощью встроенной функции max. Функция max умеет искать наибольшее значение не только для самого итерируемого объекта, но и основываясь на результах применения к нему функции. Преобразовав список во множество (см. трюк 7) и использовав метод count для нахождения числа вхождений элемента в список, получаем:
a = [1, 2, 3, 1, 2, 3, 2, 2, 4, 5, 1]
print(max(set(a), key=a.count))
2
Если необходимо найти несколько наиболее часто повторяющихся значений, воспользуйтесь счетчиком Counter из библиотеки collections:
from collections import Counter
a = [1, 2, 3, 1, 2, 3, 2, 2, 4, 5, 1]
cnt = Counter(a)
print(cnt.most_common(3))
[(2, 4), (1, 3), (3, 2)]
Метод most_common выводит список кортежей вида (элемент, число повторений). Аргумент соответствует желаемому числу кортежей. По умолчанию выводится список кортежей для всех элементов переданного списка.
16. from __future__ import
Одним из последствий популярности Python является то, что постоянно разрабатываются и выходят новые версии. Новые версии — новые возможности, но только не для вас, если вы пользуетесь устаревшей.
Впрочем, не всё так плохо. Модуль __future__ даёт возможность импортировать функциональность будущих версий Python. Это прямо как путешествие во времени, или магия:
from future import print_function
print(“Hello World!”)
17. pprint
Стандартная функция Python print()
делает своё дело. Но если попытаться вывести какой-нибудь большой вложенный объект, результат будет выглядеть не очень приятно.
Здесь на помощь приходит модуль из стандартной библиотеки pprint (pretty print). С его помощью можно выводить объекты со сложной структурой в читабельном виде.
Мастхэв для любого Python-разработчика, работающего с нестандартными структурами данных:
import requests
import pprint
url = ‘https://randomuser.me/api/?results=1’
users = requests.get(url).json()
pprint.pprint(users)
18. zip
Ещё одна клёвая штука. Когда-нибудь возникала необходимость создать словарь из двух списков?
keys = [‘a’, ‘b’, ‘c’]
vals = [1, 2, 3]
zipped = dict(zip(keys, vals))
print(zipped)
Встроенная функция zip()
принимает несколько итерируемых объектов и возвращает последовательность кортежей. Каждый кортеж группирует элементы объектов по их индексу.
Можно провести операцию, обратную zip()
, с помощью zip(*)
.
19. Просмотр встроенных функций
В стандартную библиотеку Python входит множество встроенных функций и классов. Все встроенные объекты можно посмотреть следующим образом:
for e in __builtins__.__dict__:
print(e)
20. Избегайте вложенных циклов с помощью product
Когда программа становится сложной, неизбежно приходится писать вложенные циклы. Однако вложенные циклы делают программы более сложными для чтения и сопровождения.
К счастью, в Python всегда можно избежать вложенных циклов с помощью встроенной функции product()
.
Например, у нас есть следующая программа, которая содержит трехуровневые вложенные циклы for
:
list_a = [1, 2020, 70]
list_b = [2, 4, 7, 2000]
list_c = [3, 70, 7]
for a in list_a:
for b in list_b:
for c in list_c:
if a + b + c == 2077:
print(a, b, c)
# 70 2000 7
Чтобы сделать код более аккуратным и чистым, мы можем использовать функцию product()
, которая находится в модуле itertools
, для оптимизации кода:
from itertools import product
list_a = [1, 2020, 70]
list_b = [2, 4, 7, 2000]
list_c = [3, 70, 7]
for a, b, c in product(list_a, list_b, list_c):
if a + b + c == 2077:
print(a, b, c)
# 70 2000 7
21. List comprehensions: Генераторы списков
Одна из самых удобных возможностей Python – это генераторы списков. Написанный с их помощью код выглядит очень чистым и легко читается, практически как обычный человеческий язык.
numbers = [1,2,3,4,5,6,7] evens = [x for x in numbers if x % 2 is 0] odds = [y for y in numbers if y not in evens] cities = ['Лондон', 'Дублин', 'Осло'] def visit(city): print("Добро пожаловать в " + city) for city in cities: visit(city)
Если вы хотите узнать о генераторах больше, загляните сюда.
List Comprehension — очень мощный инструмент, который создает новый список на основе другого списка в одной удобочитаемой строке.
Например, допустим, нам нужно создать список целых чисел, которые определяют длину каждого слова в определенном предложении, но только если это слово не является словом «the».
sentence = "the quick brown fox jumps over the lazy dog" words = sentence.split() word_lengths = [] for word in words: if word != "the": word_lengths.append(len(word)) print(words) print(word_lengths)
Результат:
[‘the’, ‘quick’, ‘brown’, ‘fox’, ‘jumps’, ‘over’, ‘the’, ‘lazy’, ‘dog’]
[5, 5, 3, 5, 4, 4, 3]
22. Оператор морж (:=)
или способ записывать данные в переменную о котором вы не знали
Начиная с Python 3.8, появился новый синтаксис под названием «оператор морж» или walrus operator, который может присваивать значения переменным как часть более крупного выражения.
Оператор := получил свое милое название из-за глаз и бивней моржа.
Этот синтаксис очень прост для понимания. Например, если мы хотим написать следующие две строки кода Python в одной строке, как это сделать?
author = "Yang"
print(author)
# Yang
К сожалению, мы не можем напрямую поместить присвоение в функцию print().
Если мы попытаемся это сделать, возникнет ошибка типа TypeError.
Но если мы используем оператор :=, то все получится!
print(author:="Yang")
# Yang
23. Избегайте вложенных циклов с помощью product
Когда программа становится сложной, неизбежно приходится писать вложенные циклы. Однако вложенные циклы делают программы более сложными для чтения и сопровождения.
К счастью, в Python всегда можно избежать вложенных циклов с помощью встроенной функции product()
.
Например, у нас есть следующая программа, которая содержит трехуровневые вложенные циклы for
:
list_a = [1, 2020, 70]
list_b = [2, 4, 7, 2000]
list_c = [3, 70, 7]
for a in list_a:
for b in list_b:
for c in list_c:
if a + b + c == 2077:
print(a, b, c)
# 70 2000 7
Чтобы сделать код более аккуратным и чистым, мы можем использовать функцию product()
, которая находится в модуле itertools
, для оптимизации кода:
from itertools import product
list_a = [1, 2020, 70]
list_b = [2, 4, 7, 2000]
list_c = [3, 70, 7]
for a, b, c in product(list_a, list_b, list_c):
if a + b + c == 2077:
print(a, b, c)
# 70 2000 7
24. Самый легкий способ мерджить словари
Слияние словарей – частое действие в программировании на Python. Существует множество способов сделать это. Но все они были уродливы до версии Python 3.9.
Начиная с Python 3.9, мы наконец-то получили самый элегантный способ объединения словарей – использование операторов объединения.
cities_us = {'New York City': 'US', 'Los Angeles': 'US'}
cities_uk = {'London': 'UK', 'Birmingham': 'UK'}
cities = cities_us|cities_uk
print(cities)
# {'New York City': 'US', 'Los Angeles': 'US', 'London': 'UK', 'Birmingham': 'UK'}
Как показано в примере выше, мы можем просто использовать оператор | для слияния двух разных словарей. Более того, он также поддерживает объединение in-place:
cities_us = {'New York City': 'US', 'Los Angeles': 'US'}
cities_uk = {'London': 'UK', 'Birmingham': 'UK'}
cities_us |= cities_uk
print(cities_us)
# {'New York City': 'US', 'Los Angeles': 'US', 'London': 'UK', 'Birmingham': 'UK'}
25. Используем * для мерджа списка, кортежа и множества в одну строчку
Для того, чтобы это сделать самый элегантный способ – использование *:
A = [1, 2, 3]
B = (4, 5, 6)
C = {7, 8, 9}
L = [*A, *B, *C]
print(L)
# [1, 2, 3, 4, 5, 6, 8, 9, 7]
Звездочки можно использовать в качестве префиксов для распаковки их элементов. Но помимо распаковки, звездочки также можно использовать для деструктуризации присваиваний в Python:
a, *mid, b = [1, 2, 3, 4, 5, 6]
print(a, mid, b)
# 1 [2, 3, 4, 5] 6
Как показано выше, с помощью одной звездочки переменная mid получает элементы в середине в виде списка.
26. Используем встроенные функции в Python для написания стандартной логики
В Python есть несколько встроенных функций, которые помогают при написании некоторых стандартных логических операций.
Например, функция map()
– известная и часто используемая функция. Она получает два параметра, один из которых – функция, а другой – итератор.
При выполнении функции map
функция применяется к каждому элементу в итераторе.
names = ['yAnG', 'MASk', 'thoMas', 'LISA']
names = map(str.capitalize, names)
print(list(names))
# ['Yang', 'Mask', 'Thomas', 'Lisa']
Как показано в примере выше, с помощью функции map() мы можем избежать написания цикла for для выделения заглавными буквами каждого слова в списке имен.
Другая известная функция – reduce(). Как следует из ее названия, она применяет функцию к итератору и выполняет для нее операцию reduce.
Например, в следующем примере список преобразуется в одну строку:
from functools import reduce
city = ['L', 'o', 'n', 'd', 'o', 'n', 2, 0, 2, 0]
city_to_str = reduce(lambda x, y: str(x) + str(y), city)
print(city_to_str)
# London2020
Как преобразовать строку в словарь в Python
Строковые методы split() и join() в Python
Функция sum() в Python: питонический способ суммирования значений
Как исправить ошибку NameError в Python
Однострочники Python для ускорения написания кода
5 простых способов удалить символ из строки
Задачи по Python для начинающих от Tproger и GeekBrains
Как возвести число в квадрат в Python
Кортежи в Python
Словари в Python: 12 задач для начинающих с решениями
Именованные кортежи в Python
Лямбда-функции в Python: примеры
Добавление функций в классы Python
Встроенные функции для перебора последовательностей в Python
Functools: улучшаем функции Python
Метод __repr__ в Python
22 полезных примера кода на Python
22 сниппета на Python для повседневных задач
Python Traceback — Как правильно исправлять ошибки в коде
Получение текущей даты и времени в Python
Проверить переменные среды в Python
Веселый бонус
Наверняка вы знаете про Дзен Python, выводимый интерпретатором по команде import this. В третьей версии Python спрятаны и другие «пасхалки»:
import antigravity
import __hello__