a = [10, 20, 30]
b = a
x, y, z = a # этим переменным присвоилось содержимое списка
print(x, y, z)
# Работает ли с кортежем?
c = (10, 20, 30) # с = 10, 20, 30
x, y, z = c
print(x, y, z)
print(list(range(3)))
x, y, z = range(3) # тоже работает!!!
print(x, y, z)
10 20 30 10 20 30 [0, 1, 2] 0 1 2
Т.е. можно присваивать нескольким переменным через запятую перечисления. Надо только, чтобы переменных было столько же, сколько в перечислении.
Это именно то, что происходило в цикле for key, value in d.items()
. items()
перечисляет пары (кортежи из двух элементов), получается, что мы key, value = очередная пара из перечисления
.
Очень частый шаблон в коде, обмен значений переменных:
a = 10
b = 20
# кстати, можно a, b = 10, 20
a, b = 10, 20 # справа кортеж
a, b = b, a # !! Обмен значений. Справа кортеж, слева деструктуризация
print(a, b)
x, y = [10, 20, 30] # ошибка. Слишком много значений для распаковки
--------------------------------------------------------------------------- ValueError Traceback (most recent call last) <ipython-input-9-9f5dbbbbcaa2> in <module> ----> 1 x, y = [10, 20, 30] # ошибка. Слишком много значений для распаковки ValueError: too many values to unpack (expected 2)
Что же делать, если не знаем, например, заранее длину перечисления, и не можем написать нужное количество переменных слева.
a = [10, 20, 30, 40, 50]
x, y, *z = a # здесь звездочка перед z означает, что в z присвоится весь остаток списка
print(x, y, z)
10 20 [30, 40, 50]
Неформально. Вообще, звездочка перед переменной означает превращение перечисления внутри переменной в «набор значений через запятую».
Можно звездочкой перед переменной пользоваться и в других контекстах:
z = [30, 40, 50]
a = [10, 20, *z] #
print(a)
# сравнить с
b = [10, 20, z]
print(b)
[10, 20, 30, 40, 50] [10, 20, [30, 40, 50]]
Проведем эксперименты, что если использовать не списки
a = (10, 20, 30, 40, 50)
x, y, *z = a # все равно *z присваивается список
print(x, y, z)
x, y, *z = range(10) # и здесь присвоится список
print(x, y, z)
10 20 [30, 40, 50] 0 1 [2, 3, 4, 5, 6, 7, 8, 9]
z1 = [10, 20, 30]
z2 = (10, 20, 30)
z3 = range(5)
z4 = {"abc", "eee", "hello"}
print([*z1, *z2, *z3, *z4]) # распаковываем, содержимое z как будто пишется через запятую
print({*z1, *z2, *z3, *z4}) # аналогично, создавая множества
[10, 20, 30, 10, 20, 30, 0, 1, 2, 3, 4, 'abc', 'hello', 'eee'] {0, 1, 2, 3, 4, 'hello', 'eee', 10, 'abc', 20, 30}
А со словарями?
d = {"a": 1, "b": 2, "c": 3, "d": 4}
x, *y = d # словарь если используется как перечисление, то это перечисление ключей
print(x, y)
x, *y = d.items() # перечисление пар ключ/значение
print(x, y)
a ['b', 'c', 'd'] ('a', 1) [('b', 2), ('c', 3), ('d', 4)]
print(10, 20, "abc") # три аргумента
10 20 abc
Они распечатались через пробел
print(10, 20, "abc")
print("xxx", "&&&")
10 20 abc xxx &&&
Кроме того, что распечатались через пробел, после распечатки вывелся символ перевода строки. Получается, что print печатает пробелы, переводы строк, хотя мы его не просим об этом явно. Но этим можно управлять.
print(10, 20, "abc", sep="+") # указываем, что разделять вывод надо плюсом
print(10, 20, "abc", sep="~~~")
print(10, 20, "abc", sep=".", end="%") # разделяем точкой, в конце процент
10+20+abc 10~~~20~~~abc 10.20.abc%
По умолчанию, print
считает, что sep=' '
, end='\n'
.
z = [10, 20, 30]
print(z) # печать z как список, фактически печатается str(z), потому что нужно превратить
# z в строку
print(*z) # см. ранее. * означает, что элементы как будто написаны через запятую
# эквивалентно print(10, 20, 30)
print(0, *z, 40) # эквивалентно 0, 10, 20, 30, 40
[10, 20, 30] 10 20 30 0 10 20 30 40
def f(x, y, *z):
# в этой функции должно быть два аргумента x, y, и еще сколько угодно аргументов,
# они попадут в список z
print("x =", x)
print("y =", y)
print("z =", z)
print("f1:")
f(10, 20, 30, 40, 50) # как будто x, y, *z = [10, 20, 30, 40, 50], только z кортеж
print("f2:")
f(10, 20)
print("f3:")
# f(10) # ошибка, надо указать y
f1: x = 10 y = 20 z = (30, 40, 50) f2: x = 10 y = 20 z = () f3:
Единственное, такой аргумент функции со звездочкой принято называть *args
def g(name, *args):
print("Hello,", name)
i = 1
for a in args:
print(f'argument {i} = {a}')
i = i + 1
g("Ilya", 10, "abc", [44, 55])
Hello, Ilya argument 1 = 10 argument 2 = abc argument 3 = [44, 55]
Отсутпление. Как делать цикл с перебором по индексам. Первый способ выше, завели переменную i
, которую сами изменяем. Второй способ, как в C, Pascal:
a = [10, 20, 30]
for i in range(len(a)):
print(i, a[i]) # индекс i, элемент с этим индексом
0 10 1 20 2 30
Третий способ, стандартный для python, его рекомендуется использовать:
a = [10, 20, 30]
for i, x in enumerate(a): # enumerate(a) это перечисление пар индекс/элемент
print(i, a[i])
0 10 1 20 2 30
Проверим, что делает enumerate
:
print(list(enumerate(a)))
[(0, 10), (1, 20), (2, 30)]
При вызове функций можно указывать имя аргумента:
def f(name, apples):
print(f"{name} has {apples} apples")
f("Ilya", 10)
f("Maria", 42)
f(name="Maria", apples=42) # можно аргументам указать их название
f(apples=111, name="John") # можно менять местами
f(100, apples="Andrew")
# f(apples=111, "John") # если вы начали указывать имя аргумента, дальше без имени нельзя
Ilya has 10 apples Maria has 42 apples Maria has 42 apples John has 111 apples 100 has Andrew apples
Это очень полезно для читаемости. Особенно, если аргументы логические. Сравните
some_function(10, 20, True)
или some_function(10, 20, printToFile=True)
.
Поэтому при открытии файла я рекомендую писать open("a.txt", mode="r")
вместо open("a.txt", "r")
.
def f(x, y=1):
return x + y
print(f(10, 20)) # 10 + 20
print(f(x=5, y=6)) # 5 + 6
print(f(y=6, x=5)) # 5 + 6
print(f(30)) # 30 + 1 значение y будет взято как 1, потому что это значение по-умолчанию
print(f(x=40)) # 40 + 1
# print(f(y=40)) # Ошибка, нет умолчания для x
30 11 11 31 41
Если в определении функции есть **kwargs
, в словарь kwargs
попадают все переданные в фунцию
именованные аргументы, которые не удалось присвоить другим аргументам
def f(x, y, *args, **kwargs):
print("called f")
print("x =", x)
print("y =", y)
print("args =", args)
print("kwargs =", kwargs)
def g(*args, **kwargs):
print("called g")
print("args =", args)
print("kwargs =", kwargs)
f(10, 20, 30, 40, 50, z=30, t=40) # x=10, y=20, args=(30,40,50) kwargs: {z: 30, t: 40}
f(x=10, y=20, z=30, t=40)
g(10, 20, 30, 40, x=10, y=20, z=30, t=40)
called f x = 10 y = 20 args = (30, 40, 50) kwargs = {'z': 30, 't': 40} called f x = 10 y = 20 args = () kwargs = {'z': 30, 't': 40} called g args = (10, 20, 30, 40) kwargs = {'x': 10, 'y': 20, 'z': 30, 't': 40}