Курс по Python: https://stepik.org/course/100707
На этом занятии я хочу немного отступить от темы функций и рассказать об операторах * и
**, которые мы затронули на предыдущем уроке.
Мы знаем, что они
позволяют упаковывать аргументы в кортеж и словарь. Но их можно использовать не
только в объявлении функций, но и при работе с разными коллекциями. Например,
если взять кортеж из двух значений:
то его можно
распаковать в две переменные. Но, если мы пропишем там больше значений,
например, четыре:
то уже получим
ошибку, так как элементов четыре, а переменных всего две. Но, используя
оператор *, мы можем упаковать оставшиеся значения во вторую переменную:
или, в первую,
без разницы:
То же самое
можно проделывать и со списками:
x, *y = [1, "a", True, 4]
и строками:
*x, y, z = "Hello Python!"
И вообще с
любыми итерируемыми объектами. То есть, оператор * упаковывает оставшиеся
значения в список. Правда, мы не можем упаковывать уже упакованные данные,
например, так:
произойдет
ошибка, но вот так:
уже будет
работать.
Этот же оператор
может выполнять и обратную операцию – распаковывать коллекции в набор данных.
Пусть у нас имеется список:
И на его основе
мы хотим сформировать кортеж. Если просто записать переменную в круглых
скобках:
то увидим кортеж
со списком внутри. Но, если прописать оператор * перед списком:
то произойдет
распаковка его элементов и список превратится в кортеж. То же самое можно
сделать и при вызове функций. Допустим, определим кортеж из двух значений:
и вызовем с
этими значениями функцию:
Возникнет
ошибка, так как функция ожидает числа в качестве аргументов, а не коллекции.
Но, мы можем распаковать кортеж d в два числа, поставив перед ним
оператор *:
и теперь никаких
ошибок нет. Давайте посмотрим, что вернет эта функция, преобразуем все к
списку:
Да, получаем
ожидаемые значения от -5 до 5. И, теперь, это же преобразование генератора range() в список мы
можем сделать и так:
Здорово, да?! Мы
оператором * распаковали итерируемый объект и составили из его значений список.
Мало того, мы
таким образом можем делать объединение разных коллекций в одну коллекцию,
например, список:
[*range(*d), *(True, False), *a]
Как видите,
оператор * - невероятно удобный инструмент. И те же самые действия можно делать
и со словарем. Зададим, следующий словарь с расшифровкой оценок:
d = {0: "безнадежно", 1: "убого", 2: "неуд.", 3: "удовл.", 4: "хорошо", 5: "отлично"}
Распаковать его
можно двумя способами. Если прописать один оператор *:
То получим
множество, состоящее из ключей этого словаря. Или, можно сформировать список из
ключей:
То есть,
оператор * перебирает словарь как обычный итерируемый объект и по умолчанию,
перебираются именно ключи. Если нам нужно перебрать значения, то следует
вызвать дополнительно метод:
и получим список
из значений. Соответственно, метод:
вернет кортежи
из пары ключ-значение.
Если же
требуется распаковать словарь как словарь, то перед ним следует прописать две
звездочки:
Теперь вместо
множества мы получаем словарь. Где это нам может пригодиться? Например, для
объединения нескольких словарей в один. Создадим еще один словарь:
d2 = {6: "превосходно", 7: "элитарно", 8: "божественно"}
И соединим их
через распаковку данных:
На выходе
получаем новый словарь с объединенными данными. Такой прием часто используется
на практике, когда нужно объединить сразу несколько словарей. А вот для
упаковки оператор ** не используется, если прописать, что то вроде:
то получим синтаксическую
ошибку. Можно указывать только одну звездочку. Исключение только параметр **kwargs при определении
функций.
Надеюсь, теперь
вы знаете, как работают операторы * и ** для упаковки и распаковки коллекций.
Закрепляйте все практическими заданиями и переходите к следующему уроку.
Курс по Python: https://stepik.org/course/100707