Как работает распаковка с `*`?

Распаковка с * позволяет извлекать элементы из итерируемых объектов (списков, кортежей, строк и др.) и:

  • При присваивании: Захватывает оставшиеся элементы в список. Например: first, *rest, last = [1, 2, 3, 4, 5].
  • При передаче в функцию: Распаковывает элементы итерируемого объекта как отдельные позиционные аргументы. Например: my_function(*my_list).
  • При создании новых итерируемых объектов: Объединяет элементы нескольких итерируемых объектов. Например: new_list = [*list1, *list2].

* можно использовать только один раз слева от знака равно (в левой части присваивания) и несколько раз при передаче аргументов в функцию.


Распаковка с `*` в Python – это мощный механизм, позволяющий гибко работать с итерируемыми объектами (такими как списки, кортежи, множества, и строки) при присваивании значений переменным или передаче аргументов в функции. Оператор `*` "распаковывает" элементы итерируемого объекта в отдельные значения.

Основные случаи использования:

1. Присваивание переменным:

Когда распаковка используется слева от оператора присваивания (`=`), она позволяет "захватить" несколько элементов из итерируемого объекта в одну переменную, в то время как остальные элементы присваиваются другим переменным. Переменная, помеченная `*`, становится списком, содержащим все элементы, не присвоенные другим переменным.

    
      first, *rest = [1, 2, 3, 4, 5]
      print(first)  # Выведет: 1
      print(rest)   # Выведет: [2, 3, 4, 5]

      head, *body, tail = (1, 2, 3, 4, 5)
      print(head)  # Выведет: 1
      print(body)  # Выведет: [2, 3, 4]
      print(tail)  # Выведет: 5

      *leading, last = "Hello"
      print(leading) # Выведет: ['H', 'e', 'l', 'l']
      print(last)    # Выведет: o
    
  

Важно отметить, что только одна переменная в левой части присваивания может быть помечена `*`. Если итерируемый объект содержит меньше элементов, чем количество переменных слева (без учета переменной с `*`), возникнет `ValueError`. Если элементов больше, чем требуется для остальных переменных, избыточные элементы будут присвоены переменной с `*`.

2. Передача аргументов в функции:

При вызове функции, `*` используется для распаковки итерируемого объекта в позиционные аргументы. Это позволяет передавать переменное количество аргументов в функцию.

    
      def my_function(a, b, c):
        print(f"a: {a}, b: {b}, c: {c}")

      my_list = [1, 2, 3]
      my_function(*my_list)  # Эквивалентно my_function(1, 2, 3)
      # Выведет: a: 1, b: 2, c: 3

      def sum_all(*args):
        total = 0
        for arg in args:
          total += arg
        return total

      print(sum_all(1, 2, 3, 4))  # Выведет: 10
    
  

3. Объединение итерируемых объектов:

`*` можно использовать для объединения нескольких итерируемых объектов в один список, кортеж или множество (в последнем случае будут удалены дубликаты).

    
      list1 = [1, 2, 3]
      list2 = [4, 5, 6]
      combined_list = [*list1, *list2]
      print(combined_list)  # Выведет: [1, 2, 3, 4, 5, 6]

      tuple1 = (1, 2)
      tuple2 = (3, 4)
      combined_tuple = (*tuple1, *tuple2)
      print(combined_tuple) # Выведет: (1, 2, 3, 4)

      set1 = {1, 2, 3}
      set2 = {3, 4, 5}
      combined_set = {*set1, *set2}
      print(combined_set) # Выведет: {1, 2, 3, 4, 5}
    
  

4. Игнорирование значений:

Можно использовать `*` с `_` (подчеркиванием) для игнорирования определенных элементов итерируемого объекта.

    
      first, *_, last = [1, 2, 3, 4, 5]
      print(first)  # Выведет: 1
      print(last)   # Выведет: 5
    
  

Дополнительно:

  • Python 3.5 ввел `*` и `**` операторы для распаковки итерируемых объектов и словарей соответственно при вызове функции, что значительно улучшило читаемость кода.
  • `**` оператор используется для распаковки словарей в именованные аргументы функции.

В целом, распаковка с `*` – это универсальный и удобный инструмент для работы с итерируемыми объектами в Python, который делает код более кратким и читаемым.

0