К примеру, что делает * (астериск) в следующем коде:
print(*min(p for p in counter.items() if p[1] == max_count))
print(*team, *coef)
seasons = [datetime(*args) for args in [
(Y, 1, 1), # winter
(Y, 3, 1), # spring
(Y, 6, 1), # summer
(Y, 9, 1), # autumn
(Y, 12, 1) # winter
]]
def lcm(*args):
"""Least common multiple."""
return reduce(lambda a, b: a * b // gcd(a, b), args)
async def watchdog(loop, last_activity_time, timeout, func, *args):
"Run *func(*args)* if more than *timeout* seconds since *last_activity_time*."
while (loop.time() - last_activity_time()) < timeout:
await asyncio.sleep(1)
return func(*args)
и что делают две ** звёздочки:
'{a:.{n}f}'.format(**vars())
class A:
def __init__(self, a, **kwargs):
super().__init__(**kwargs)
Ответ
Звёздочка в Питоне помимо умножения x*y (help('*')) и возведения
в степень x**y
(help('**'))†
используется, чтобы обозначить ноль или более чего-либо.
К примеру в описании параметров функции:
def f(*args):
print(args)
* означает, что функция принимает ноль или более аргументов,
которые доступны внутри функции в виде кортежа args
>>> f(1,'a')
(1, 'a')
Для именованных параметров используются две
звёздочки
def g(a, b, *args, name='default', **kwargs):
print(a, b, args, name, kwargs)
здесь g() принимает два обязательных аргумента и произвольное (ноль или более) количество
других аргументов:
>>> g(1, b=2, c=3)
1 2 () default {'c': 3}
kwargs—это словарь дополнительных аргументов, переданных по имени (c в данном случае). А
args это пустой кортеж (), так как дополнительных позиционных
аргументов не было передано.
После * все параметры обязаны передаваться по имени,
пример
def min_item(items, *, key=lambda x: x):
...
При вызове, если задан, key обязан быть указан по имени:
min([1,2,-3], key=abs)
Принятие произвольного количества аргументов может быть полезно при
создании функций-обёрток:
def my_print(*args, **kwargs):
flush = kwargs.pop('flush', True) # flush unless overriden
print(*args, flush=flush, **kwargs)
При множественном наследовании
**kwargs помогает
реализовать требование совместимости параметров для методов базовых классов, так как kwargs позволяет передать произвольные именованные аргументы.
Видно, что звёздочку можно использовать и при вызове
функции
L = [1, 2, 3]
s = "abc"
print(*L, *s) # iterable unpacking: print(1, 2, 3, 'a', 'b', 'c')
# -> 1 2 3 a b c
произвольные коллекции (iterable в общем случае) L, s распаковываются и каждый их элемент передаётся в виде отдельного агрумента в вызываемую функцию (print()).
Можно использовать и при явном присваивании:
>>> first, *middle, last = L
>>> first, middle, last
(1, [2], 3)
в этом случае первый и последний аргументы из списка L распаковываются в явно
приведённые имена (first, last), а остаток ноль или более
элементов в виде списка помещаются в middle
Звёздочку можно использовать и при задании списков, кортежей, наборов и
словарей в исходном коде, используя соответствующий синтаксис (tuple,
list, set, and dictionary
displays):
>>> *range(4), 4
(0, 1, 2, 3, 4)
>>> [*range(4), 4]
[0, 1, 2, 3, 4]
>>> {*range(4), 4}
{0, 1, 2, 3, 4}
>>> {'x': 1, **{'y': 2}} # dictionary unpacking inside dictionary display
{'x': 1, 'y': 2}
Тонкий момент: запятая в Питоне создаёт кортеж—скобки нужны только для
пустого кортежа (). Поэтому первая строчка равнозначна: (*range(4), 4)
Так же как и при вызове функций, звёздочка распаковывает коллекцию здесь и действует как будто каждый элемент был передан отдельно в соответствующие конструкторы.
Таким образом можно сложить два
словаря или произвольные отображения (Mapping):
>>> a = {'a': 1, 'b': 2}
>>> b = {'a': 3, 'c': 0}
>>> {**a, **b}
{'a': 3, 'b': 2, 'c': 0}
>>> {**b, **a}
{'a': 1, 'c': 0, 'b': 2}
При наличии дублирующих ключей, более поздние значения побеждают, как обычно: {'a': 1, 'a': 3} == {'a': 3}
Знание, что делает звёздочка полезно, чтобы объяснить как zip(*matrix) транспонирует квадратную матрицу или как обойти итератор по ровно n элементов за раз: zip(*[iterator]*n)
Помимо указанных значений, звёздочка может присутствовать в имени
файла для создания шаблона (wildcard), к
примеру
from pathlib import Path
print(*Path().glob('*.py'))
print(*Path().glob('**/*.py'))
Первый print() печатает через пробел все (ноль или более) имена файлов в текущей директории с расширением .py. Подобный (*.py) синтаксис популярен, так как он используется в командной строке (shell).
Второй print() с двумя звёздочками ('**/*.py') выводит имена Питон-файлов во всем дереве директорий (включая вложенные директории).
В регулярных
выражениях
* означает повторение ноль или более раз:
import re
if re.fullmatch(r'x*', text):
print('текст пустой или содержит только `x`')
† умножение натуральных чисел n*m можно рассматривать как повторение сложения (ноль или более) раз. Аналогично, возведение в степень n**m можно рассматривать как повторение умножения:
2 * 3 == 2 + 2 + 2
2 ** 3 == 2 * 2 * 2
[2] * 3 == [2, 2, 2]
Комментариев нет:
Отправить комментарий