Use of *args and **kwargs
Так что у меня возникли трудности с концепцией *args
а также **kwargs
,
До сих пор я узнал, что:
*args
= список аргументов - как позиционные аргументы**kwargs
= словарь - ключи которого становятся отдельными аргументами ключевых слов, а значения становятся значениями этих аргументов.
Я не понимаю, для какой задачи программирования это было бы полезно.
Может быть:
Я думаю, чтобы ввести списки и словари в качестве аргументов функции и одновременно с подстановочным знаком, чтобы я мог передать любой аргумент?
Есть простой пример, чтобы объяснить, как *args
а также **kwargs
используются?
Также в учебнике, который я нашел, использовались только "*" и имя переменной.
Являются *args
а также **kwargs
просто заполнители или вы используете точно *args
а также **kwargs
в коде?
11 ответов
Синтаксис является *
а также **
, Имена *args
а также **kwargs
только по соглашению, но нет строгого требования использовать их.
Вы бы использовали *args
когда вы не уверены, сколько аргументов может быть передано вашей функции, т.е. это позволяет вам передавать произвольное количество аргументов в вашу функцию. Например:
>>> def print_everything(*args):
for count, thing in enumerate(args):
... print( '{0}. {1}'.format(count, thing))
...
>>> print_everything('apple', 'banana', 'cabbage')
0. apple
1. banana
2. cabbage
Так же, **kwargs
позволяет обрабатывать именованные аргументы, которые вы не определили заранее:
>>> def table_things(**kwargs):
... for name, value in kwargs.items():
... print( '{0} = {1}'.format(name, value))
...
>>> table_things(apple = 'fruit', cabbage = 'vegetable')
cabbage = vegetable
apple = fruit
Вы можете использовать их вместе с именованными аргументами. Явные аргументы сначала получают значения, а затем все остальное передается *args
а также **kwargs
, Именованные аргументы идут первыми в списке. Например:
def table_things(titlestring, **kwargs)
Вы также можете использовать оба в одном и том же определении функции, но *args
должно произойти до **kwargs
,
Вы также можете использовать *
а также **
синтаксис при вызове функции. Например:
>>> def print_three_things(a, b, c):
... print( 'a = {0}, b = {1}, c = {2}'.format(a,b,c))
...
>>> mylist = ['aardvark', 'baboon', 'cat']
>>> print_three_things(*mylist)
a = aardvark, b = baboon, c = cat
Как вы можете видеть в этом случае, он берет список (или кортеж) предметов и распаковывает их. Этим он сопоставляет их с аргументами в функции. Конечно, вы могли бы иметь *
как в определении функции, так и в вызове функции.
Одно место, где использование *args
а также **kwargs
Это довольно полезно для подклассов.
class Foo(object):
def __init__(self, value1, value2):
# do something with the values
print value1, value2
class MyFoo(Foo):
def __init__(self, *args, **kwargs):
# do something else, don't care about the args
print 'myfoo'
super(MyFoo, self).__init__(*args, **kwargs)
Таким образом, вы можете расширить поведение класса Foo без необходимости слишком много знать о Foo. Это может быть очень удобно, если вы программируете на API, который может измениться. MyFoo просто передает все аргументы в класс Foo.
Вот пример, который использует 3 различных типа параметров.
def func(required_arg, *args, **kwargs):
# required_arg is a positional-only parameter.
print required_arg
# args is a tuple of positional arguments,
# because the parameter name has * prepended.
if args: # If args is not empty.
print args
# kwargs is a dictionary of keyword arguments,
# because the parameter name has ** prepended.
if kwargs: # If kwargs is not empty.
print kwargs
>>> func()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: func() takes at least 1 argument (0 given)
>>> func("required argument")
required argument
>>> func("required argument", 1, 2, '3')
required argument
(1, 2, '3')
>>> func("required argument", 1, 2, '3', keyword1=4, keyword2="foo")
required argument
(1, 2, '3')
{'keyword2': 'foo', 'keyword1': 4}
Вот одно из моих любимых мест, чтобы использовать **
синтаксис как в последнем примере Дейва Уэбба:
mynum = 1000
mystr = 'Hello World!'
print "{mystr} New-style formatting is {mynum}x more fun!".format(**locals())
Я не уверен, что это ужасно быстро, если сравнивать с использованием только самих имен, но его гораздо проще набирать!
Один из случаев, когда *args и **kwargs полезны, - это при написании функций-оболочек (таких как декораторы), которые должны иметь возможность принимать произвольные аргументы для передачи в оборачиваемую функцию. Например, простой декоратор, который печатает аргументы и возвращаемое значение оборачиваемой функции:
def mydecorator( f ):
@functools.wraps( f )
def wrapper( *args, **kwargs ):
print "Calling f", args, kwargs
v = f( *args, **kwargs )
print "f returned", v
return v
return wrapper
*args и ** kwargs - это особые магические возможности Python. Подумайте о функции, которая может иметь неизвестное количество аргументов. Например, по каким-либо причинам вы хотите иметь функцию, которая суммирует неизвестное число чисел (и вы не хотите использовать встроенную функцию суммы). Итак, вы пишете эту функцию:
def sumFunction(*args):
result = 0
for x in args:
result += x
return result
и используйте его как: sumFunction (3,4,6,3,6,8,9).
** Кваргс имеет разную функцию. С помощью ** kwargs вы можете давать произвольные ключевые аргументы функции и обращаться к ним как к диктонарному.
def someFunction(**kwargs):
if 'text' in kwargs:
print kwargs['text']
Вызов someFunction(text="foo") выведет foo.
Просто представьте, что у вас есть функция, но вы не хотите ограничивать количество параметров, которые она принимает. Пример:
>>> import operator
>>> def multiply(*args):
... return reduce(operator.mul, args)
Затем вы используете эту функцию как:
>>> multiply(1,2,3)
6
or
>>> numbers = [1,2,3]
>>> multiply(*numbers)
6
Имена *args
а также **kwargs
или же **kw
чисто по соглашению. Это облегчает нам чтение кода друг друга
Это удобно, когда вы используете модуль struct
struct.unpack()
возвращает кортеж, тогда как struct.pack()
использует переменное количество аргументов. При манипулировании данными удобно иметь возможность передавать кортеж struck.pack()
например.
tuple_of_data = struct.unpack(format_str, data)
... manipulate the data
new_data = struct.pack(format_str, *tuple_of_data)
без этой способности вы были бы вынуждены написать
new_data = struct.pack(format_str, tuple_of_data[0], tuple_of_data[1], tuple_of_data[2],...)
это также означает, что если format_str изменится и размер кортежа изменится, мне придется вернуться и отредактировать эту действительно длинную строку
Обратите внимание, что *args/**kwargs является частью синтаксиса вызова функций, а не оператором. Это имеет особый побочный эффект, с которым я столкнулся: нельзя использовать расширение * args с оператором print, поскольку print не является функцией.
Это кажется разумным:
def myprint(*args):
print *args
К сожалению, он не компилируется (синтаксическая ошибка).
Это компилирует:
def myprint(*args):
print args
Но выводит аргументы в виде кортежа, а это не то, что мы хотим.
Это решение, на котором я остановился:
def myprint(*args):
for arg in args:
print arg,
print
Эти параметры обычно используются для прокси-функций, поэтому прокси-сервер может передавать любой входной параметр целевой функции.
def foo(bar=2, baz=5):
print bar, baz
def proxy(x, *args, **kwargs): # reqire parameter x and accept any number of additional arguments
print x
foo(*args, **kwargs) # applies the "non-x" parameter to foo
proxy(23, 5, baz='foo') # calls foo with bar=5 and baz=foo
proxy(6)# calls foo with its default arguments
proxy(7, bar='asdas') # calls foo with bar='asdas' and leave baz default argument
Но поскольку эти параметры скрывают фактические имена параметров, их лучше избегать.
Вы можете взглянуть на документацию по python (docs.python.org в FAQ), но более конкретно для хорошего объяснения загадочные мисс арг и мистер кваргс (любезно предоставлены archive.org) (оригинальная, мертвая ссылка здесь).
В двух словах, оба используются, когда используются необязательные параметры для функции или метода. Как говорит Дейв, *args используется, когда вы не знаете, сколько аргументов может быть передано, и **kwargs, когда вы хотите обработать параметры, заданные именем и значением, как в:
myfunction(myarg=1)