def args(normal_arg, *argv):
print ("normal argument:",normal_arg)
for arg in argv:
print("Argument in list of arguments from *argv:", arg)
args('animals','fish','duck','bird')
会产生:
normal argument: animals
Argument in list of arguments from *argv: fish
Argument in list of arguments from *argv: duck
Argument in list of arguments from *argv: bird
def who(**kwargs):
if kwargs is not None:
for key, value in kwargs.items():
print ("Your %s is %s." %(key,value))
who (name="Nikola", last_name="Tesla", birthday = "7.10.1856", birthplace = "Croatia")
会产生:
Your name is Nikola.
Your last_name is Tesla.
Your birthday is 7.10.1856.
Your birthplace is Croatia.
39
*(双星)和(星)对参数做了什么
它们允许 functions to be defined to accept 和 users to pass 任意数量的参数,位置( * )和关键字( ** ) .
>>> foo(1,2,3,4,5, kwarg2='kwarg2', foo='foo', bar='bar')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
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 "<stdin>", line 1, in <module>
TypeError: bar() takes 0 positional arguments but 1 was given
以下函数描述了它们的使用方式,并演示了行为 . 请注意,命名的 b 参数将被第二个位置参数消耗之前:
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 <type 'tuple'> and length 2
unknown arg: 3
unknown arg: 4
kwargs is of type <type 'dict'> 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}
Example 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) 打印:
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 <type 'tuple'> and length 0
kwargs is of type <type 'dict'> 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}
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
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
def sum(a,b): #receive args from function calls as sum(1,2) or sum(a=1,b=2)
print(a+b)
my_tuple = (1,2)
my_list = [1,2]
my_dict = {'a':1,'b':2}
# Let us unpack data structure of list or tuple or dict into arguments with help of '*' operator
sum(*my_tuple) # becomes same as sum(1,2) after unpacking my_tuple with '*'
sum(*my_list) # becomes same as sum(1,2) after unpacking my_list with '*'
sum(**my_dict) # becomes same as sum(a=1,b=2) after unpacking by '**'
# output is 3 in all three calls to sum function.
所以记住
'*'或'**'运算符用于 function call 时 -
'*'运算符将数据结构(如列表或元组)解包为函数定义所需的参数 .
'**'运算符将字典解包为函数定义所需的参数 .
现在让我们研究 function definition 中的'*'运算符 . 例:
def sum(*args): #pack the received positional args into data structure of tuple. after applying '*' - def sum((1,2,3,4))
sum = 0
for a in args:
sum+=a
print(sum)
sum(1,2,3,4) #positional args sent to function sum
#output:
10
在函数 definition 中,'*'运算符将接收的参数打包到元组中 .
现在让我们看一下函数定义中使用的'**'的示例:
def sum(**args): #pack keyword args into datastructure of dict after applying '**' - def sum({a:1,b:2,c:3,d:4})
sum=0
for k,v in args.items():
sum+=v
print(sum)
sum(a=1,b=2,c=3,d=4) #positional args sent to function sum
在函数 definition 中'**'运算符将接收的参数打包到字典中 .
所以请记住:
在 function call 元数据的'*' unpacks 数据结构或列表中的函数定义接收的位置或关键字参数 .
在 function call 中'**' unpacks 将字典数据结构转换为由函数定义接收的位置或关键字参数 .
def __init__(self, *args, **kwargs):
for attribute_name, value in zip(self._expected_attributes, args):
setattr(self, attribute_name, value)
if kwargs.has_key(attribute_name):
kwargs.pop(attribute_name)
for attribute_name in kwargs.viewkeys():
setattr(self, attribute_name, kwargs[attribute_name])
那么子类就可以了
class RetailItem(Item):
_expected_attributes = Item._expected_attributes + ['name', 'price', 'category', 'country_of_origin']
class FoodItem(RetailItem):
_expected_attributes = RetailItem._expected_attributes + ['expiry_date']
class ElectronicAccessories(RetailItem):
_expected_attributes = RetailItem._expected_attributes + ['specifications']
# Depend on args and kwargs to populate the data as needed.
def __init__(self, specifications = None, *args, **kwargs):
self.specifications = specifications # Rest of attributes will make sense to parent class.
super(ElectronicAccessories, self).__init__(*args, **kwargs)
这个例子可以帮助你一次记住Python中的 *args , **kwargs 甚至 super 和继承 .
class base(object):
def __init__(self, base_param):
self.base_param = base_param
class child1(base): # inherited from base class
def __init__(self, child_param, *args) # *args for non-keyword args
self.child_param = child_param
super(child1, self).__init__(*args) # call __init__ of the base class and initialize it with a NON-KEYWORD arg
class child2(base):
def __init__(self, child_param, **kwargs):
self.child_param = child_param
super(child2, self).__init__(**kwargs) # call __init__ of the base class and initialize it with a KEYWORD arg
c1 = child1(1,0)
c2 = child2(1,base_param=0)
print c1.base_param # 0
print c1.child_param # 1
print c2.base_param # 0
print c2.child_param # 1
18 回答
*args
和**kwargs
是允许任意数量的函数参数的常用习惯用法,如Python文档中的more on defining functions部分所述 .*args
将为您提供所有函数参数as a tuple:**kwargs
将为所有 keyword arguments 提供除了与形式参数相对应的字典之外的所有内容 .这两个习语都可以与普通参数混合,以允许一组固定和一些变量参数:
调用函数时,
*l
习语的另一个用法是 unpack argument lists .在Python 3中,可以在赋值的左侧使用
*l
(Extended Iterable Unpacking),尽管它在此上下文中给出了一个列表而不是一个元组:Python 3也增加了新的语义(参考PEP 3102):
这样的函数只接受3个位置参数,
*
之后的所有内容只能作为关键字参数传递 .** args = ** aDict = dict中的所有项目
虽然在Python 3中使用星形/ splat运算符已经expanded,但我喜欢下表,因为它与使用这些运算符with functions有关 . splat运算符可以在函数构造和函数调用中使用:
这真的只是总结了Lorin Hochstein的answer,但我觉得它很有帮助 .
*args
和**kwargs
:允许您将可变数量的参数传递给函数 .*args
:用于向函数发送非keyworded变长参数列表:会产生:
**kwargs*
**kwargs
允许您将keyworded变量长度的参数传递给函数 . 如果要在函数中处理命名参数,则应使用**kwargs
.会产生:
它们允许 functions to be defined to accept 和 users to pass 任意数量的参数,位置(
*
)和关键字(**
) .定义功能
*args
允许任意数量的可选位置参数(参数),这些参数将分配给名为args
的元组 .**kwargs
允许任意数量的可选关键字参数(参数),这些参数将位于名为kwargs
的dict中 .您可以(并且应该)选择任何适当的名称,但如果目的是使参数具有非特定语义,则
args
和kwargs
是标准名称 .扩展,传递任意数量的参数
您还可以使用
*args
和**kwargs
分别从列表(或任何可迭代)和dicts(或任何映射)传入参数 .接收参数的函数不必知道它们正在被扩展 .
例如,Python 2的xrange没有明确地期望
*args
,但是因为它需要3个整数作为参数:另一个例子,我们可以在
str.format
中使用dict扩展:Python 3中的新功能:使用仅关键字参数定义函数
你可以在
*args
之后有keyword only arguments - 例如,这里,kwarg2
必须作为关键字参数给出 - 而不是位置:用法:
此外,
*
可以单独用于指示仅关键字参数,而不允许无限制的位置参数 .在这里,
kwarg2
必须再次是一个显式命名的关键字参数:而且我们不能再接受无限制的位置论证,因为我们没有
*args*
:同样,更简单地说,这里我们要求
kwarg
由名称给出,而不是在位置上:在这个例子中,我们看到如果我们尝试在位置上传递
kwarg
,我们会收到一个错误:我们必须显式传递
kwarg
参数作为关键字参数 .Python 2兼容演示
*args
(通常表示"star-args")和**kwargs
(可以通过说"kwargs"暗示星星,但是"double-star kwargs"明确表示)是使用*
和**
表示法的Python的常用习语 . 这些特定的变量名称不是必需的(例如,您可以使用*foos
和**bars
),但偏离惯例可能会激怒您的Python同事 .当我们不知道我们的函数将要接收什么或者我们可能传递多少个参数时,我们通常会使用这些,有时即使分别命名每个变量也会变得非常混乱和冗余(但这种情况通常是明确的比隐含更好 .
Example 1
以下函数描述了它们的使用方式,并演示了行为 . 请注意,命名的
b
参数将被第二个位置参数消耗之前:我们可以通过
help(foo)
查看函数签名的在线帮助,它告诉我们让我们用
foo(1, 2, 3, 4, e=5, f=6, g=7)
调用此函数打印:
Example 2
我们也可以使用另一个函数调用它,我们只提供
a
:bar(100)
打印:Example 3: practical usage in decorators
好吧,也许我们还没有看到效用 . 因此,假设在差分代码之前和/或之后,您有多个具有冗余代码的函数 . 以下命名函数仅用于说明目的的伪代码 .
我们可能能够以不同的方式处理这个问题,但我们当然可以使用装饰器提取冗余,因此下面的示例演示了
*args
和**kwargs
如何非常有用:现在,每个包装函数都可以更简洁地编写,因为我们已经考虑了冗余:
通过分解我们的代码(
*args
和**kwargs
允许我们这样做),我们减少了代码行数,提高了可读性和可维护性,并为程序中的逻辑提供了唯一的规范位置 . 如果我们需要改变这个结构的任何部分,我们有一个地方可以进行每次更改 .def foo(param1, *param2):
是一个方法可以接受*param2
的任意数量的值,def bar(param1, **param2):
是一个方法,可以使用*param2
的键接受任意数量的值param1
是一个简单的参数 .例如,在Java中实现 varargs 的语法如下:
让我们首先了解什么是位置参数和关键字参数 . 下面是 Positional arguments. 的函数定义示例
所以这是一个带位置参数的函数定义 . 您也可以使用关键字/命名参数调用它:
现在让我们用 keyword arguments 学习一个函数定义的例子:
您也可以使用位置参数调用此函数:
所以我们现在知道具有位置和关键字参数的函数定义 .
现在让我们研究'*'运算符和'**'运算符 .
请注意,这些运营商可以在两个方面使用:
a) function call
b) function definition
在 function call. 中使用'*'运算符和'**'运算符
让我们直接举一个例子然后讨论它 .
所以记住
'*'或'**'运算符用于 function call 时 -
'*'运算符将数据结构(如列表或元组)解包为函数定义所需的参数 .
'**'运算符将字典解包为函数定义所需的参数 .
现在让我们研究 function definition 中的'*'运算符 . 例:
在函数 definition 中,'*'运算符将接收的参数打包到元组中 .
现在让我们看一下函数定义中使用的'**'的示例:
在函数 definition 中'**'运算符将接收的参数打包到字典中 .
所以请记住:
在 function call 元数据的'*' unpacks 数据结构或列表中的函数定义接收的位置或关键字参数 .
在 function call 中'**' unpacks 将字典数据结构转换为由函数定义接收的位置或关键字参数 .
在一个 function definition '*' packs 位置参数进入元组 .
在 function definition 中'**' packs 关键字参数进入字典 .
对于那些通过实例学习的人!
*
的目的是让您能够定义一个函数,该函数可以将任意数量的参数作为列表提供(例如f(*myList)
) .**
的目的是让您能够通过提供字典(例如f(**{'x' : 1, 'y' : 2})
)来提供函数的参数 .让我们通过定义一个带有两个正常变量
x
,y
的函数来表明这一点,并且可以接受更多的参数为myArgs
,并且可以接受更多的参数为myKW
. 稍后,我们将展示如何使用myArgDict
提供y
.警告
**
专门用于词典 .首先发生非可选参数赋值 .
您不能两次使用非可选参数 .
如果适用,
**
必须始终在*
之后 .*
表示接收变量参数作为列表**
表示接收变量参数作为字典使用如下:
**1) single ***
Output:
**2) Now ****
Output:
我想举一个其他人没有提到过的例子
*也可以打开 generator
Python3文档中的一个示例
unzip_x将是[1,2,3],unzip_y将是[4,5,6]
zip()接收多个iretable args,并返回一个生成器 .
在函数中使用两者的一个很好的例子是:
同样值得注意的是,在调用函数时也可以使用
*
和**
. 这是一个快捷方式,允许您使用列表/元组或字典直接将多个参数传递给函数 . 例如,如果您有以下内容功能:你可以这样做:
注意:
mydict
中的键必须与函数foo
的参数完全相同 . 否则会抛出一个TypeError
:在Python 3.5中,您还可以在
list
,dict
,tuple
和set
显示(有时也称为文字)中使用此语法 . 见PEP 488: Additional Unpacking Generalizations .它还允许在单个函数调用中解压缩多个迭代 .
(感谢mgilson的PEP链接 . )
*
和**
在函数参数列表中有特殊用法 .*
表示该参数是一个列表,**
表示该参数是一个字典 . 这允许函数接受任意数量的参数除了函数调用之外,* args和** kwargs在类层次结构中很有用,也避免了在Python中编写
__init__
方法 . 在类似Django代码的框架中可以看到类似的用法 .例如,
那么子类就可以了
然后将子类实例化为
此外,具有仅对该子类实例有意义的新属性的子类可以调用Base类
__init__
来卸载属性设置 . 这是通过* args和** kwargs完成的 . kwargs主要用于使用命名参数可读取代码 . 例如,可以实例化为
完整的代码是here
单*表示可以有任意数量的额外位置参数 .
foo()
可以像foo(1,2,3,4,5)
一样调用 . 在foo()的主体中,param2是一个包含2-5的序列 .双**表示可以有任意数量的额外命名参数 .
bar()
可以像bar(1, a=2, b=3)
一样调用 . 在bar()的主体中,param2是一个包含{'a':2,'b':3}的字典使用以下代码:
输出是
从Python文档:
这个例子可以帮助你一次记住Python中的
*args
,**kwargs
甚至super
和继承 .