我观察到,大部分新的Python程序员都需要花上大量时间理解清楚 *args
和**kwargs
这两个魔法变量。那么它们到底是什么?
其实,并不是一定需要将他们下城*args
和**kwargs
。只有它们前面的*(星号)是必须的,你可以写成*var和**vars,那为什么大家都写成*args
和**kwargs
呢?那只是一个约定俗成的命名。
*args的用法
*args
主要是在函数定义的时候使用的,如果你的函数中使用了*args
这个参数,那么你就可以穿无穷多个参数给定义的函数。举个栗子
def test_var_args(f_arg, *argv):
print("first normal arg:", f_arg)
for arg in argv:
print("another arg through *argv:", arg)
test_var_args('yasoob', 'python', 'eggs', 'test')
输出结果如下:
another arg through *argv: python
another arg through *argv: eggs
another arg through *argv: test
我们再来看一个栗子
def test_args(*args):
ret = 0
for i in args:
ret += i
return ret
sums = test_args(1, 2, 3, 4, 5)
print(sums)
输出结果如下:
希望这两个例子解决了你的疑惑,接下来我们看看**kwargs这个参数
**kwargs的用法
**kwargs
允许你将不定长度的键值对, 作为参数传递给一个函数。 如果你想要在一个函数里处理带名字的参数, 你应该使用**kwargs
。
举一个例子
def greet_me(**kwargs):
for key, value in kwargs.items():
print("{0} == {1}".format(key, value))
>>> greet_me(name="yasoob")
name == yasoob
现在你可以看出我们怎样在一个函数里, 处理了一个键值对参数了。
这就是**kwargs
的基础, 而且你可以看出它有多么管用。 接下来让我们谈谈,你怎样使用*args
和 **kwargs
来调用一个参数为列表或者字典的函数。
使用 args 和 *kwargs 来调用函数
那现在我们将看到怎样使用*args
和**kwargs
来调用一个函数。 假设,你有这样一个小函数:
def test_args_kwargs(arg1, arg2, arg3):
print("arg1:", arg1)
print("arg2:", arg2)
print("arg3:", arg3)
你可以使用*args
或**kwargs
来给这个小函数传递参数。 下面是怎样做:
# 首先使用 *args
>>> args = ("two", 3, 5)
>>> test_args_kwargs(*args)
arg1: two
arg2: 3
arg3: 5
# 现在使用 **kwargs:
>>> kwargs = {"arg3": 3, "arg2": "two", "arg1": 5}
>>> test_args_kwargs(**kwargs)
arg1: 5
arg2: two
arg3: 3
使用时的顺序
如果你想在函数中同事使用这三种参数,他们的顺序是这样的
some_func(fargs, *args, **kwargs)
啥时候使用它们
这还真的要看你的需求而定。最常见的用例是在写函数装饰器的时候。
此外它也可以用来做猴子补丁(monkey patching)。猴子补丁的意思是在程序运行时(runtime)修改某些代码。 打个比方,你有一个类,里面有个叫get_info
的函数会调用一个API并返回相应的数据。如果我们想测试它,可以把API调用替换成一些测试数据。例如:
import someclass
def get_info(self, *args):
return "Test data"
someclass.get_info = get_info
在装饰器中使用它们
我们之前讲过一点点装饰器的内容,现在我们来看看如何在装饰器中使用这两个参数
首先我们定义一个装饰器函数
import time
def run_time(func):
def wrap():
st = time.time()
result = func()
print('{} function running spend time is {}'.format(func.__name__, time.time() - st))
return result
return wrap
老生常谈,上面定义了一个计算方法运行时间的装饰器。
然后写两个函数并装饰一下。
@run_time
def test1():
time.sleep(3)
@run_time
def test2():
time.sleep(4)
输出结果如下所示L:
test2 function running spend time is 4.002828359603882
在这里有一个问题,因为我写的两个函数都是不带参数的,但是如果带参数呢。
@run_time
def test1(a):
print('{} function input parameter is {}'.format(__name__, a))
time.sleep(3)
@run_time
def test2(a):
print('{} function input parameter is {}'.format(__name__, a))
time.sleep(4)
test1(12)
test2(31)
这时候再去装饰函数就会报如下错误
这是因为我们在装饰函数中没有带参数,这时候我们修改一下装饰器函数如下
def run_time(func):
def wrap(a):
st = time.time()
result = func(a)
print('{} function running spend time is {}'.format(func.__name__, time.time() - st))
return result
return wrap
再次运行,输出结果如下所示
test1 function running spend time is 3.0007827281951904
test2 function input parameter is 31
test2 function running spend time is 4.002350568771362
虽然解决了我们上面的问题,但是如果我需要再定义一个函数,代码如下
@run_time
def test3(a, b):
print('{}+{}={}'.format(a, b, a + b))
time.sleep(1)
这时候我们在运行代码,会出现如下报错,这是因为我们test3函数有两个参数了,装饰器函数传递的参数不够,所以出现报错了。
这时候,我们的*args与**kwargs就派上用场了。我们将装饰器函数修改为如下
def run_time(func):
def wrap(*args, **kwargs):
st = time.time()
result = func(*args, **kwargs)
print('{} function running spend time is {}'.format(func.__name__, time.time() - st))
return result
return wrap
再次运行,我们就可以得到正确的结果了。这时,不管你装饰的函数参数有多么的变化,都可以使用这个装饰器来进行装饰。
test1 function input parameter is 12 test1 function running spend time is 3.0029850006103516 test2 function input parameter is 31 test2 function running spend time is 4.002876043319702 12+23=35 test3 function running spend time is 1.0011005401611328
Macv 博主 2020-11-09T16:02:29
试试emoji表情???