*args与**kwargs的含义

2020-11-03 19:09:03 Python 356

简介

在学习Python的时候,我们肯定都遇到过*args以及**kwargs这两个东西。我们都知道这表示可变参数以及可变位置参数的意思,但是它的真正用处在哪里呢?今天简单的解释一下,大家一起学习一下。

我观察到,大部分新的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')

输出结果如下: 

first normal arg: yasoob
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)

 输出结果如下:

15

 希望这两个例子解决了你的疑惑,接下来我们看看**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: 

test1 function running spend time is 3.0014431476593018
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 input parameter is 12
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
您尚未登录, 登录注册 后评论

当前共有2条评论


清水 博主

试试emoji表情🤙🤙🤙