Что делает
**
(двойная звезда) и*
(звезда) для параметровОни позволяют определять функции для принятия и для пользователей проходить любое число аргументов, positional (
*
) и ключевое слово (**
).Определяющие функции
*args
допускают любое количество необязательных позиционных аргументов (параметров), который будет присвоен кортежу с именемargs
.
**kwargs
допускает любое количество необязательных аргументов (параметров) ключевого слова, которые будут находиться в имени dictkwargs
.Вы можете (и должны) выбрать любое подходящее имя , но если целью является аргумент неспецифической семантики,
args
иkwargs
являются стандартными именами.Расширение, Передача любого количества аргументов
Вы также могут использовать
*args
и**kwargs
для передачи параметров из списков (или любого итеративного) и dicts (или любого сопоставления) соответственно.Функция, получающая параметры, не должна знать, что они расширяются.
Например, xrange Python 2 явно не ожидает
*args
, но поскольку в качестве аргументов он принимает 3 целых числа:>>> x = xrange(3) # create our *args - an iterable of 3 integers >>> xrange(*x) # expand here xrange(0, 2, 2)
В качестве другого примера мы можем использовать расширение dict в
str.format
:>>> foo = 'FOO' >>> bar = 'BAR' >>> 'this is foo, {foo} and bar, {bar}'.format(**locals()) 'this is foo, FOO and bar, BAR'
Новое в Python 3: Определение функций только с ключевыми аргументами
После [f0] ключевого слова можно использовать только - например, здесь
kwarg2
должен быть задан как аргумент ключевого слова - не позиционно:def foo(arg, kwarg=None, *args, kwarg2=None, **kwargs): return arg, kwarg, args, kwarg2, kwargs
Использование:
>>> foo(1,2,3,4,5,kwarg2='kwarg2', bar='bar', baz='baz') (1, 2, (3, 4, 5), 'kwarg2', {'bar': 'bar', 'baz': 'baz'})
Также можно использовать
*
def foo(arg, kwarg=None, *, kwarg2=None, **kwargs): return arg, kwarg, kwarg2, kwargs
Здесь
kwarg2
снова должен быть явно именованным аргументом ключевого слова:>>> foo(1,2,kwarg2='kwarg2', foo='foo', bar='bar') (1, 2, 'kwarg2', {'foo': 'foo', 'bar': 'bar'})
И мы больше не можем принимать неограниченные позиционные аргументы, потому что у нас нет
*args*
:>>> foo(1,2,3,4,5, kwarg2='kwarg2', foo='foo', bar='bar') Traceback (most recent call last): File "
", line 1, in TypeError: foo() takes from 1 to 2 positional arguments but 5 positional arguments (and 1 keyword-only argument) were given Опять же, здесь мы требуем, чтобы
kwarg
указывался по имени, а не по положению :def bar(*, kwarg=None): return kwarg
В этом примере мы видим, что если мы попытаемся передать
kwarg
позиционно, мы получим ошибку:>>> bar('kwarg') Traceback (most recent call last): File "
", line 1, in TypeError: bar() takes 0 positional arguments but 1 was given We должен явно передать параметр
kwarg
в качестве аргумента ключевого слова.>>> bar(kwarg='kwarg') 'kwarg'
Совместимые с Python демки
*args
(обычно называемые «star-args») и**kwargs
(звезды могут подразумеваться, говоря «kwargs», но быть явным с «двойными звездами») являются общими идиомами Python для использования нот*
и**
. Эти конкретные имена переменных не требуются (например, вы могли бы использовать*foos
и**bars
), но отклонение от конвенции может вызвать возмущение у ваших коллег-программистов Python.Обычно мы используем их, когда мы не знаем, что получит наша функция, или сколько аргументов мы можем передавать, а иногда даже при наименовании каждой переменной отдельно получилось бы очень грязное и избыточное (но это это случай, когда обычно явный лучше, чем неявный).
Пример 1
Следующая функция описывает, как их можно использовать и демонстрирует поведение. Обратите внимание, что именованный аргумент
b
будет потребляться вторым аргументом position before:def foo(a, b=10, *args, **kwargs): ''' this function takes required argument a, not required keyword argument b and any number of unknown positional arguments and keyword arguments after ''' print('a is a required argument, and its value is {0}'.format(a)) print('b not required, its default value is 10, actual value: {0}'.format(b)) # we can inspect the unknown arguments we were passed: # - args: print('args is of type {0} and length {1}'.format(type(args), len(args))) for arg in args: print('unknown arg: {0}'.format(arg)) # - kwargs: print('kwargs is of type {0} and length {1}'.format(type(kwargs), len(kwargs))) for kw, arg in kwargs.items(): print('unknown kwarg - kw: {0}, arg: {1}'.format(kw, arg)) # But we don't have to know anything about them # to pass them to other functions. print('Args or kwargs can be passed without knowing what they are.') # max can take two or more positional args: max(a, b, c...) print('e.g. max(a, b, *args) \n{0}'.format( max(a, b, *args))) kweg = 'dict({0})'.format( # named args same as unknown kwargs ', '.join('{k}={v}'.format(k=k, v=v) for k, v in sorted(kwargs.items()))) print('e.g. dict(**kwargs) (same as {kweg}) returns: \n{0}'.format( dict(**kwargs), kweg=kweg))
Мы можем проверить онлайн-справку для подписи функции с помощью
help(foo)
, которая сообщает намfoo(a, b=10, *args, **kwargs)
Назовем эту функцию с помощью
foo(1, 2, 3, 4, e=5, f=6, g=7)
, который печатает:
a is a required argument, and its value is 1 b not required, its default value is 10, actual value: 2 args is of type
and length 2 unknown arg: 3 unknown arg: 4 kwargs is of type and length 3 unknown kwarg - kw: e, arg: 5 unknown kwarg - kw: g, arg: 7 unknown kwarg - kw: f, arg: 6 Args or kwargs can be passed without knowing what they are. e.g. max(a, b, *args) 4 e.g. dict(**kwargs) (same as dict(e=5, f=6, g=7)) returns: {'e': 5, 'g': 7, 'f': 6} Пример 2
Мы также можем назвать это с помощью другого функция, в которую мы просто предоставляем
a
:def bar(a): b, c, d, e, f = 2, 3, 4, 5, 6 # dumping every local variable into foo as a keyword argument # by expanding the locals dict: foo(**locals())
bar(100)
prints:a is a required argument, and its value is 100 b not required, its default value is 10, actual value: 2 args is of type
and length 0 kwargs is of type and length 4 unknown kwarg - kw: c, arg: 3 unknown kwarg - kw: e, arg: 5 unknown kwarg - kw: d, arg: 4 unknown kwarg - kw: f, arg: 6 Args or kwargs can be passed without knowing what they are. e.g. max(a, b, *args) 100 e.g. dict(**kwargs) (same as dict(c=3, d=4, e=5, f=6)) returns: {'c': 3, 'e': 5, 'd': 4, 'f': 6} Пример 3: практическое использование в декораторах
Хорошо, так что, возможно, мы еще не видим утилиту. Итак, представьте, что у вас есть несколько функций с избыточным кодом до и / или после дифференцирующего кода. Следующие именованные функции являются просто псевдокодом для иллюстративных целей.
def foo(a, b, c, d=0, e=100): # imagine this is much more code than a simple function call preprocess() differentiating_process_foo(a,b,c,d,e) # imagine this is much more code than a simple function call postprocess() def bar(a, b, c=None, d=0, e=100, f=None): preprocess() differentiating_process_bar(a,b,c,d,e,f) postprocess() def baz(a, b, c, d, e, f): ... and so on
Мы могли бы обрабатывать это по-другому, но мы можем, конечно, извлечь избыточность с помощью декоратора, и поэтому наш приведенный ниже пример демонстрирует, как
*args
и**kwargs
могут быть очень полезными:def decorator(function): '''function to wrap other functions with a pre- and postprocess''' @functools.wraps(function) # applies module, name, and docstring to wrapper def wrapper(*args, **kwargs): # again, imagine this is complicated, but we only write it once! preprocess() function(*args, **kwargs) postprocess() return wrapper
И теперь каждая завернутая функция может быть написана гораздо более лаконично, поскольку мы учли избыточность:
@decorator def foo(a, b, c, d=0, e=100): differentiating_process_foo(a,b,c,d,e) @decorator def bar(a, b, c=None, d=0, e=100, f=None): differentiating_process_bar(a,b,c,d,e,f) @decorator def baz(a, b, c=None, d=0, e=100, f=None, g=None): differentiating_process_baz(a,b,c,d,e,f, g) @decorator def quux(a, b, c=None, d=0, e=100, f=None, g=None, h=None): differentiating_process_quux(a,b,c,d,e,f,g,h)
И, разглаживая наш код, который позволяет нам делать
*args
и**kwargs
, мы сокращаем строки кода, улучшаем читаемость и ремонтопригодность и имеем единственные канонические места для логики нашей программы. Если нам нужно изменить какую-либо часть этой структуры, у нас есть одно место, в которое можно внести каждое изменение.
В первом тестовом случае оператор присваивания не используется. Он просто использует форму инициализации, называемую «инициализация копирования». При инициализации объекта инициализация кода не рассматривает явные конструкторы.
struct A {
A();
// explicit copy constructor
explicit A(A const&);
// explicit constructor
explicit A(int);
// non-explicit "converting" constructor
A(char const*c);
};
A a;
A b = a; // fail
A b1(a); // succeeds, "direct initialization"
A c = 1; // fail, no converting constructor found
A d(1); // succeeds
A e = "hello"; // succeeds, converting constructor used
Инициализация копирования используется в тех случаях, которые соответствуют неявным преобразованиям, где явно не запускается преобразование, как при передаче аргумента функции и возврате из функции.
Стандарт C ++ 8.5 / 12
Инициализация, возникающая при передаче аргументов, возврат функции, исключение (15.1), обработка исключения (15.3) и список инициализаторов, заключенных в фигурные скобки ( 8.5.1) называется копией-инициализацией и эквивалентна форме
T x = a;
Инициализация, возникающая в новых выражениях (5.3.4), static_cast выражениях (5.2.9), преобразования типов функциональных обозначений (5.2.3), а начальные и членные инициализаторы (12.6.2) называются прямой инициализацией и эквивалентны форме
blockquote>T x(a);
Ваш первый набор соответствует стандарту C ++ и не связан с некоторой оптимизацией.
Раздел 12.8 ([class.copy]
) стандарта C ++ дает аналогичный пример:
class X {
// ...
public:
X(int);
X(const X&, int = 1);
};
X a(1); // calls X(int);
X b(a, 0); // calls X(const X&, int);
X c = b; // calls X(const X&, int);
Последняя строка будет соответствовать вашему случаю.