前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >python--一文搞懂参数args,kwargs

python--一文搞懂参数args,kwargs

原创
作者头像
languageX
发布2023-04-03 14:58:04
4.9K2
发布2023-04-03 14:58:04
举报
文章被收录于专栏:计算机视觉CV计算机视觉CV

函数传参是最常用的方法,但是你真的掌握python里参数的传递和使用了吗?之前文章我们介绍了传参的拷贝情况,会不会引起传入参数的变化。本文详细介绍python的函数中*args, **kwargs的使用。

一 *在python中的作用

首先我们了解下python里*操作符主要有哪些作用。

1. 数学运算符

常用的数学操作符,比如乘法day_seconds = 24*60*60,次方 5**2=25

2. 解包,收集列表中多余的值

代码语言:javascript
复制
def test_splat():
    a = [1, 2, 3]
    # 这里*a之将a解包到新列表
    b = [*a, 4, 5, 6]
    # [1, 2, 3]
    print("splat list a", a)
    # 1, 2, 3
    print("splat list *a", *a)
    # [1,2,3,4,5,6]
    print("splat list b", b)

    val_1, val_2, *list_3 = b
    # 1
    print("splat val_1", val_1)
    # 2
    print("splat val_2", val_2)
    # [3, 4, 5, 6]
    print("splat list_3", list_3)

如上代码所示,*a就是将列表[1,2,3]解包为1,2,3

3. 函数定义和函数调用

本文重点就是介绍*的第三个作用:在函数定义和调用的使用。

在定义函数时,*代表收集参数,**代表收集关键字参数;

在调用函数时,*和**都是分配参数用的。

* args 和 ** kwargs 主要用于函数定义,你可以将不定数量的参数传递给一个函数。这里不定的意思是: 预先并不知道,函数使用者会传递多少个参数给你,所在在这个场景下使用这两个关键字。

*args (arguments)表示任何多个无名参数, 它本质上是一个 tuple

** kwargs (keyword arguments)表示关键字参数, 它本质上是一个 dict

注意:使用时必须要求 *args 参数列要在** kwargs 前面 【因为位置参数在关键字参数的前面。】

二 args 和 ** kwargs的用法实例

下面我们用一些实例来熟悉* args 和 ** kwargs的用法。

1. arg参数

最简单的传参用法, 参数个数和位置意义对应,但是如果是不定长参数个数,比如配置项,这种传参方法就不适用了

代码语言:javascript
复制
def test_arg(x, y, z):
    print("test_arg", x, y ,z)
test_arg(1, 2, 3)

2. *args不定长参数个数

代码语言:javascript
复制
def test_args(*args):
    print("test_args args", args, type(args))
    for arg in args:
        print("test_args arg", arg)

我们可以将参数直接传入

代码语言:javascript
复制
test_args("x", "y", 1, 2, 3, [1.0])
输出:
test_args args ('x', 'y', 1, 2, 3, [1.0]) <class 'tuple'>
test_args arg x
test_args arg y
test_args arg 1
test_args arg 2
test_args arg 3
test_args arg [1.0]

也可以直接传入一个变量,那传入args和解包后的*args区别是什么呢

代码语言:javascript
复制
args = 1, 2, 3
test_args(args)
输出:
test_args args ((1, 2, 3),) <class 'tuple'>
test_args arg (1, 2, 3)

输出:
test_args(*args)
test_args args (1, 2, 3) <class 'tuple'>
test_args arg 1
test_args arg 2
test_args arg 3

知识点:args = 1, 2, 3 是元组类型,做为元组类型作为参数传递,不解包就是一个整体;所以传入元组参数应该传入解包后的*args

3. **kargs变长的带关键字参数

代码语言:javascript
复制
def test_kargs(**kargs):
    print("test_kargs kargs", kargs, type(kargs))
    for key,item in kargs.items():
        print("test_kargs", key,item)
代码语言:javascript
复制
 test_kargs(a="a", b="b", c=1, d=[1,2])
 kargs = (a="a", b="b", c=1, d=[1,2]})
 test_kargs(**kargs)
 输出:
 test_kargs kargs {'a': 'a', 'b': 'b', 'c': 1, 'd': [1, 2]} <class 'dict'>
test_kargs a a
test_kargs b b
test_kargs c 1
test_kargs d [1, 2]

知识点:kargs是字典类型,传入字典参数应该传入解包后的**kargs

4. arg和*arg混用

代码语言:javascript
复制
def test_arg_args_case1(x, y, *args):
    print("test_arg_args x", x)
    print("test_arg_args y", y)
    print("test_arg_args args", args)

def test_arg_args_case2(x, *args, y):
    print("test_arg_args x", x)
    print("test_arg_args y", y)
    print("test_arg_args args", args)
    
test_arg_args_case1("x", "y", 1, "A", [1, 2])
test_arg_args_case2("x", 1, "A", [1, 2], y="y")

知识点1: 按照位置,*args在最后,前面是对应位置的参数,剩下的为变长*args

知识点2: 如果*args不在最后,则需要在参数传入时,明确定义 *args后面的变量参数名

5. *args 和 **kargs 混合使用

代码语言:javascript
复制
def test_args_kwargs_case1(*args, **kwargs):
    print("args", args, type(args))
    print("kwargs", kwargs, type(kwargs))
代码语言:javascript
复制
args = 1, 2, 3
kargs = {"arg1":1, "arg2":2,"arg3":3}
test_args_kwargs_case1(1, 2, 3, arg1 = 1, arg2= 2, arg3 = 3)
输出:
args (1, 2, 3) <class 'tuple'>
kwargs {'arg1': 1, 'arg2': 2, 'arg3': 3} <class 'dict'>

test_args_kwargs_case1(args, kargs)
输出:
args ((1, 2, 3), {'arg1': 1, 'arg2': 2, 'arg3': 3}) <class 'tuple'>
kwargs {} <class 'dict'>
注意所有参数作为一个tuple传给了*args

test_args_kwargs_case1(args, **kargs)
输出:
args ((1, 2, 3),) <class 'tuple'>
kwargs {'arg1': 1, 'arg2': 2, 'arg3': 3} <class 'dict'>
注意,后面的**kargs作为无名参数字典传入,前面传入的是未解包的args元组

test_args_kwargs_case1(*args, **kargs)
输出:
args (1, 2, 3) <class 'tuple'>
kwargs {'arg1': 1, 'arg2': 2, 'arg3': 3} <class 'dict'>
正确的传入方式

知识点0:传入的是解包后的*args,作为带关键字参数,才会输出args (1, 2, 3) <class 'tuple'>

知识点1:传入的是解包后的**kargs,作为带关键字参数,才会输出kwargs {'arg1': 1, 'arg2': 2, 'arg3': 3} <class 'dict'>

知识点2:顺序:必须*args在**kargs之前 test_args_kwargs_case2(**kwargs, *args) 编译报错 * parameter after ** parameter

6. arg, *args 和 **kargs混用

代码语言:javascript
复制
def test_arg_args_kwargs1(first_arg, *args, second_arg , **kwargs):
    print("first_arg", first_arg)
    print("second_arg", second_arg)
    print("args", args[0], args[1], args, type(args))
    print("kwargs", kwargs, type(kwargs))

def test_arg_args_kwargs2(*args, first_arg, second_arg , **kwargs):
    print("first_arg", first_arg)
    print("second_arg", second_arg)
    print("args", args[0], args[1], args, type(args))
    print("kwargs", kwargs, type(kwargs))


def test_arg_args_kwargs3(first_arg, second_arg ,*args, **kwargs):
    print("first_arg", first_arg)
    print("second_arg", second_arg)
    print("args", args[0], args[1], args, type(args))
    print("kwargs", kwargs, type(kwargs))

代码语言:javascript
复制
args = 1,2,3
kwargs = {"arg1":1, "arg2":2,"arg3":3}
# 报错,必须是无关键字在有关键字之前
# test_arg_args_kwargs1(first_arg=1, *args, second_arg=2, **kwargs)
test_arg_args_kwargs2(*args, first_arg=1, second_arg=2, **kwargs)
test_arg_args_kwargs3(1, 2, *args, **kwargs)

知识点1:顺序必须是无关键字在有关键字之前

比如:*args, 带关键字arg, **kwargs; arg, *args, **kwargs

建议最好按arg, *args, **kwargs的顺序传入

三 默认值参数的用法实例

有时候传入参数会使用一些默认值参数,这里也简单介绍下默认值的使用规则。

代码语言:javascript
复制
def test_default_value(num1, num2=2, num3=3):
    return  num1 + num2 + num3
sum = test_default_value(1)

知识点:带默认值参数的后面都需要带默认值,参数顺序:不带默认值,带默认值

代码语言:javascript
复制
from typing import Optional
def test_option_type(num1: int, num2: int,num3: Optional[int] = None):
    return  num1 + num2 + num3

知识点:

规定默认值时,不一定要声明变量所属的类型(说到底Python中的对象、变量名只是一个指针或者说地址罢了),Python是一门动态语言,它总会在Python解释器进程运行的时候去动态地判定一个变量赋值的类型,而之所以在代码中声明静态类型则是为了减少人为错误而提供相应的类型或错误提示,但并不会影响Python的运行!

代码语言:javascript
复制
from typing import Optional
def test_option_type(num1: int, num2: int,num3: Optional[int] = None):
    return  num1 + num2 + num3

知识点:

可选类型,作用几乎和带默认值的参数等价,不同的是使用Optional会告诉你的IDE或者框架:这个参数除了给定的默认值外还可以是None,而且使用有些静态检查工具如mypy时,对 a: int =None这样类似的声明可能会提示报错,但使用a :Optional[int] = None不会。

四 使用*作为返回值

如果我们要返回多个参数,一般是如下写法

代码语言:javascript
复制
def test_return_args():
    return 1,2,3,4,5,6
代码语言:javascript
复制
a,b,c,d,e,f = test_return_args()
print(a,b,c,d,e,f)
a, b, _, _, _, _ = test_return_args()
print(a, b,_)
a, b, *_ = test_return_args()
print(a, b, *_)

如果是多个参数中,我们不同调用时刻是想用不同的参数,其他属于冗余参数,可以使用_定义。

如果嫌弃太多冗余太麻烦,就可以使用*_将多余参数进行压包。

那万一我有时候想要a,b,e呢。。还是要很多冗余_,代码不易理解。这里就可以使用具名元组。

五 使用具名元组

代码语言:javascript
复制
def test_namedtuple():
    # 构建具名元组
    Point = namedtuple('Point', ['x', 'y', 'z', 'value'])
    # 添加值,实例化
    p1 = Point(1, 1, 1, 5)
    p2 = Point(x=1, y=2, z=4, value=4)
    # 解包字典
    dict = {'x': 1, 'y': 2, 'z': 3, 'value':4}
    
    point = Point(**dict)
    return point
代码语言:javascript
复制
# 多个返回参数,可以使用具名元组
point = test_namedtuple()
print("out", point, point[0], point.x)
输出:
out Point(x=1, y=2, z=3, value=4) 1 1

知识点:namedtuple比dict的优点是,其具有有序性,不可变只读。

参考:

https://blog.csdn.net/qq_44683653/article/details/108990873

https://blog.csdn.net/zkk9527/article/details/88675129

https://blog.csdn.net/GODSuner/article/details/117961990

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一 *在python中的作用
    • 1. 数学运算符
      • 2. 解包,收集列表中多余的值
        • 3. 函数定义和函数调用
        • 二 args 和 ** kwargs的用法实例
          • 1. arg参数
            • 2. *args不定长参数个数
              • 3. **kargs变长的带关键字参数
                • 4. arg和*arg混用
                  • 5. *args 和 **kargs 混合使用
                    • 6. arg, *args 和 **kargs混用
                    • 三 默认值参数的用法实例
                    • 四 使用*作为返回值
                    • 五 使用具名元组
                    领券
                    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档