Привет, Хабр! В этой статье я продемонстрирую 5 трюков Python на понятных для новичков примерах, которые помогут вам писать более элегантный Python код в вашей повседневной работе.

1. Избегайте вложенных циклов с помощью 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

2. Оператор морж (:=) или способ записывать данные в переменную о котором вы не знали

Начиная с Python 3.8, появился новый синтаксис под названием «оператор морж» или walrus operator, который может присваивать значения переменным как часть более крупного выражения.

Оператор := получил свое милое название из-за глаз и бивней моржа.

Этот синтаксис очень прост для понимания. Например, если мы хотим написать следующие две строки кода Python в одной строке, как это сделать?

author = "Yang"
print(author)
# Yang

К сожалению, мы не можем напрямую поместить присвоение в функцию print(). Если мы попытаемся это сделать, возникнет ошибка типа TypeError. Но если мы используем оператор :=, то все получится!

print(author:="Yang")
# Yang

3. Самый легкий способ мерджить словари

Слияние словарей - частое действие в программировании на 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'}

4. Используем * для мерджа списка, кортежа и множества в одну строчку

Для того, чтобы это сделать самый элегантный способ - использование *:

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 получает элементы в середине в виде списка.

5. Используем встроенные функции в 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 и Machine Learning в современных сервисах можно посмотреть в моем телеграм канале. Я пишу про разработку, ML, стартапы и релокацию в UK для IT специалистов.

Комментарии (15)


  1. longclaps
    04.02.2023 11:00
    +28

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

    Отнюдь не всегда:

    for a in range(3):
        for b in range(a):
            for c in range(a + b):
                print(a, b, c)
    

    Гнать таких знаек в шею ссаными тряпками.


  1. Vindicar
    04.02.2023 11:25
    +12

    1. Зачастую менее очевидно, чем циклы. Реально имеет смысл, только если циклов больше 3х, или если количество циклов заранее неизвестно. Условно, перебор всех строк из N символов в заданном алфавите.
    2. У моржа очень ограниченная область применения, где он не делает хуже. Смешивать два разнородных действия в одной строке - такая себе идея.
    3. Для слияния двух словарей в третий имеет смысл. Для обновления существующего словаря update() всё ещё предпочтительнее.
    4. Вот этот синтаксис интересен. Не знал.
    5. А вот тут лучше бы сделать акцент на том, как устроены методы в питоне. Точнее, что это функции, которые явно получают self - и практически всё. Именно поэтому "hello".captialize() и str.capitalize("hello") работает одинаково, используя один и тот же код. И в ряде случаев это поведение имеет смысл использовать - не только для строк, но и для объектов других классов. Разумеется, это работает только для методов без параметров (помимо self). В противном случае всё равно придётся использовать лямбды или functools.partial().


    1. Survtur
      04.02.2023 14:44

      4. Вот этот синтаксис интересен. Не знал.

      Возможно вам понравится аналогичный синтаксис со словарями:

      a = {"w": 5, "x": 6}
      b = {"y": 7}
      c = {"z": 8, **a, **b}


    1. WASD1
      04.02.2023 16:38
      -1

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

      a, *mid, b = [1, 2, 3, 4, 5, 6]
      print(a, mid, b)
      # 1 [2, 3, 4, 5] 6


    1. funca
      04.02.2023 21:58
      +1

      5 примеры вообще антипаттерн. В своё время они изгоняли map/reduce в пользу list comprehension где это возможно и добавили правило в pylint.


  1. igor6130
    04.02.2023 13:26
    +6

    К сожалению, мы не можем напрямую поместить присвоение в функцию print().

    А зачем это вообще нужно?


    1. vassabi
      04.02.2023 14:19

      если вам действительно интересно - это сделано для if( ... ) \ while (..) и т.д.

      #
      # как было раньше
      #
      some_filter_res = filter_func(data)
      if (some_filter_res):
        # работаем с >>>some_filter_res<<<
        ... 
      # some_filter_res - пуст и не нужен
      
      
      #
      # а теперь с оператором моржа
      #
      
      if (some_filter_res := filter_func(data)):
        # работаем с >>>some_filter_res<<<
        ... 
      

      я думаю для while - еще нагляднее пример :)


      1. igor6130
        04.02.2023 14:51
        +9

        Я в курсе, что такое моржовый оператор. Мне было непонятно, зачем он в принте и почему автор по этому поводу так сокрушается.


      1. Melirius
        06.02.2023 13:43

        То есть то, на что ругаются в C?


  1. fireSparrow
    04.02.2023 15:44
    +8

    Подскажите, а вот на КДПВ комментарий через два слэша — это какой-то новый синтаксис в питоне?


    1. Survtur
      04.02.2023 17:00
      +7

      Есть такой способ - перед тем, как уйти на перерыв, оставить явную ошибку в том месте, на котором ты остановился. Чтобы IDE всё подчёркивало красными цветами и ничего не запускалось/не компилировалось.

      Возможно это тот случай


  1. danilovmy
    05.02.2023 02:56
    +9

    Ахаха. Решил отправить свое недовольство лажовыми примерами непрямую автору статьи на medium. Оказывается, он меня уже забанил за то, что я отправлял ему свое недовольство лажовыми примерами.

    This user had blocked you from following them or viewing their stories.

    Странно, что, еще никто не написал, что пример в "5." это ''.join((str(bit) for bit in city))


    1. manfredima
      06.02.2023 13:37
      +1

      ''.join(map(str, city))


      1. danilovmy
        06.02.2023 14:33

        красиво.


  1. MonsterCatz
    06.02.2023 16:49

    Оставлю, вдруг кому тоже пригодится.

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

    names = ['yAnG', 'MASk', 'thoMas', 'LISA']

    print('{} {} {} {}'.format(*names))


    print(('{} ' * len(names)).format(*names))