Что означают * args и ** kwargs?
Что именно означают *args
и **kwargs
?
Согласно документации Python, из того, что кажется, она проходит в кортеже аргументов.
def foo(hello, *args):
print hello
for each in args:
print each
if __name__ == '__main__':
foo("LOVE", ["lol", "lololol"])
Это выдает:
LOVE
['lol', 'lololol']
Как вы их эффективно используете?
Ответы
Ответ 1
Помещение *args
и/или **kwargs
в качестве последних элементов в списке аргументов определений функций позволяет этой функции принимать произвольное количество аргументов и/или аргументы ключевых слов.
Например, если вы хотите написать функцию, которая вернула сумму всех своих аргументов, независимо от того, сколько вы предоставляете, вы можете написать ее следующим образом:
def my_sum(*args):
return sum(args)
Вероятно, он чаще всего используется в объектно-ориентированном программировании, когда вы переопределяете функцию и хотите вызвать исходную функцию с любыми аргументами, которые пользователь передает.
Вам не нужно называть их args
и kwargs
, это просто соглашение. Его *
и **
, которые делают магию.
Официальная документация на Python имеет более подробный вид.
Ответ 2
Кроме того, мы используем их для управления наследованием.
class Super( object ):
def __init__( self, this, that ):
self.this = this
self.that = that
class Sub( Super ):
def __init__( self, myStuff, *args, **kw ):
super( Sub, self ).__init__( *args, **kw )
self.myStuff= myStuff
x= Super( 2.7, 3.1 )
y= Sub( "green", 7, 6 )
Таким образом, Sub не знает (или не заботится) о том, что такое инициализация суперкласса. Если вы понимаете, что вам нужно изменить суперкласс, вы можете исправить ситуацию, не пытаясь потровать детали в каждом подклассе.
Ответ 3
Обратите внимание на замечательную вещь в комментарий S.Lott - вы можете также вызывать функции с *mylist
и **mydict
для распаковки позиционных и ключевых слов:
def foo(a, b, c, d):
print a, b, c, d
l = [0, 1]
d = {"d":3, "c":2}
foo(*l, **d)
Будет напечатан: 0 1 2 3
Ответ 4
Еще одно полезное использование для *args
и **kwargs
: вы можете определить общие функции "catch all", что отлично подходит для декораторов, где вы возвращаете такую оболочку вместо исходной функции.
Пример с тривиальным декодером кеширования:
import pickle, functools
def cache(f):
_cache = {}
def wrapper(*args, **kwargs):
key = pickle.dumps((args, kwargs))
if key not in _cache:
_cache[key] = f(*args, **kwargs) # call the wrapped function, save in cache
return _cache[key] # read value from cache
functools.update_wrapper(wrapper, f) # update wrapper metadata
return wrapper
import time
@cache
def foo(n):
time.sleep(2)
return n*2
foo(10) # first call with parameter 10, sleeps
foo(10) # returns immediately
Ответ 5
Просто, чтобы прояснить, как распаковать аргументы и позаботиться о отсутствующих аргументах и т.д.
def func(**keyword_args):
#-->keyword_args is a dictionary
print 'func:'
print keyword_args
if keyword_args.has_key('b'): print keyword_args['b']
if keyword_args.has_key('c'): print keyword_args['c']
def func2(*positional_args):
#-->positional_args is a tuple
print 'func2:'
print positional_args
if len(positional_args) > 1:
print positional_args[1]
def func3(*positional_args, **keyword_args):
#It is an error to switch the order ie. def func3(**keyword_args, *positional_args):
print 'func3:'
print positional_args
print keyword_args
func(a='apple',b='banana')
func(c='candle')
func2('apple','banana')#It is an error to do func2(a='apple',b='banana')
func3('apple','banana',a='apple',b='banana')
func3('apple',b='banana')#It is an error to do func3(b='banana','apple')
Ответ 6
Посмотрите на http://agiliq.com/blog/2012/06/understanding-args-and-kwargs/
Его просто то, что вы хотели, я думаю