深入理解Python中的魔法参数 *args 和 **kwargs

news2024/11/15 19:34:21

在Python编程中,函数的灵活性是其强大之处之一。其中,*args 和 **kwargs 是实现函数参数可变性的重要工具。

在这里插入图片描述

无论我们是Python初学者还是经验丰富的开发者,充分理解这两个概念都有助于编写更加灵活、高效的代码。

本文将深入探讨*args和**kwargs的用法、原理和应用场景,以全面掌握它们。

一、初识 *args 和 **kwargs

*args 和 **kwargs 都是python中的可变参数。

*args可以用来表示任何多个无名参数,本质上是元组类型。

**kwargs可以用来表示关键字参数,本质上是字典类型。

在这里插入图片描述

1. 什么是 *args?

*args 允许函数接受任意数量的位置参数,这些参数会以元组的形式传入函数内部。

args是“arguments”(参数)的缩写,但名称并非固定,关键在于星号*。

示例:

def sum_numbers(*args):
    total = 0
    for number in args:
        total += number
    return total

print(sum_numbers(1, 2, 3))  # 输出:6

2. 什么是 **kwargs?

**kwargs 允许函数接受任意数量的关键字参数,这些参数会以字典的形式传入函数内部。

kwargs是“keyword arguments”(关键字参数)的缩写,同样,名称不固定,关键在于双星号**。

示例:

def greet(**kwargs):
    for key, value in kwargs.items():
        print(f"{key} = {value}")

greet(name='Alice', age=30)
# 输出:
# name = Alice
# age = 30

二、深入理解 *args

1. 使用场景

参数数量未知:当您定义的函数需要接受不定数量的位置参数时,*args非常有用。

函数包装器:在编写装饰器或高阶函数时,需要传递参数给被装饰函数。

2. 工作原理

当函数定义中包含*args时,传入的所有位置参数都会被收集到一个元组中,您可以像处理元组一样处理args。

示例:

def display_args(first_arg, *args):
    print("第一个参数:", first_arg)
    print("其他参数:", args)

display_args(10, 20, 30, 40)
# 输出:
# 第一个参数: 10
# 其他参数: (20, 30, 40)

3. 注意事项

*args必须放在函数定义参数列表的最后,除非还有**kwargs。

在调用函数时,不能使用关键字参数传递给*args。

三、深入理解 **kwargs

1. 使用场景

参数名未知:当函数需要接受任意数量的关键字参数,且参数名在定义时未知。

配置参数:处理配置项或可选参数。

2. 工作原理

函数定义中包含**kwargs时,所有的关键字参数都会被收集到一个字典中,您可以像处理字典一样处理kwargs。

示例:

def display_kwargs(**kwargs):
    for key, value in kwargs.items():
        print(f"{key} : {value}")

display_kwargs(name='祖冲之', age=25, country='China')
# 输出:
# name : 祖冲之
# age : 25
# country : China

3. 注意事项

**kwargs必须放在函数定义参数列表的最后。

在函数调用时,关键字参数的名称必须是有效的Python标识符。

四、同时使用 *args 和 **kwargs

1. 函数定义顺序

在函数定义中,参数的顺序必须为:

  • 位置参数(必需参数)

  • 默认参数(可选参数)

  • *args(可变位置参数)

  • **kwargs(可变关键字参数)

示例:

def func(a, b=2, *args, **kwargs):
    print("a =", a)
    print("b =", b)
    print("args =", args)
    print("kwargs =", kwargs)

func(1, 3, 5, 7, x=10, y=20)
# 输出:
# a = 1
# b = 3
# args = (5, 7)
# kwargs = {'x': 10, 'y': 20}

2. 应用场景

最大化函数的灵活性:允许函数接受任意类型和数量的参数。

编写通用代码:如装饰器、日志记录器等,需要处理不同的函数签名。

五、参数解包与传递

1. 位置参数的解包(*)

将序列(如列表、元组)中的元素解包为单独的参数传递给函数。

示例:

def add(a, b, c):
    return a + b + c

numbers = [1, 2, 3]
result = add(*numbers)  # 等价于 add(1, 2, 3)
print(result)  # 输出:6

2. 关键字参数的解包(**)

将字典中的键值对解包为关键字参数传递给函数。

示例:

def introduce(name, age, country):
    print(f"我叫{name},今年{age}岁,来自{country}。")

info = {'name': 'Charlie', 'age': 28, 'country': 'China'}
introduce(**info)
# 输出:我叫Charlie,今年28岁,来自China。

3. 同时解包

示例:

def func(a, b, c, d):
    print(a, b, c, d)

args = (1, 2)
kwargs = {'c': 3, 'd': 4}
func(*args, **kwargs)
# 输出:1 2 3 4

六、在装饰器中的应用

1. 为什么在装饰器中使用?

装饰器需要能够装饰任意函数,无论其参数如何定义。

使用*args和**kwargs,可以编写一个通用的装饰器,适用于所有函数。

2. 编写通用装饰器

示例:

def logger(fn):
    def wrapper(*args, **kwargs):
        print(f"正在调用函数 {fn.__name__},参数:args={args}, kwargs={kwargs}")
        result = fn(*args, **kwargs)
        print(f"函数 {fn.__name__} 调用完毕,返回值:{result}")
        return result
    return wrapper

@logger
def multiply(a, b):
    return a * b

@logger
def greet(name, message='Hello'):
    return f"{message}, {name}!"

multiply(3, 4)
# 输出:
# 正在调用函数 multiply,参数:args=(3, 4), kwargs={}
# 函数 multiply 调用完毕,返回值:12

greet(name='Alice')
# 输出:
# 正在调用函数 greet,参数:args=(), kwargs={'name': 'Alice'}
# 函数 greet 调用完毕,返回值:Hello, Alice!

3. 深入理解

*args和**kwargs的传递:装饰器内部的wrapper函数接受*args和**kwargs,并将其传递给被装饰的函数fn。

保持函数签名:这样,装饰器不会改变原函数的参数要求。

七、实际应用案例

1. 参数校验

使用*args和**kwargs,可以编写装饰器来检查参数的类型或值。

示例:

def type_check(fn):
    def wrapper(*args, **kwargs):
        for arg in args:
            if not isinstance(arg, int):
                raise TypeError("所有参数必须是整数")
        return fn(*args, **kwargs)
    return wrapper

@type_check
def add_integers(*args):
    return sum(args)

print(add_integers(1, 2, 3))  # 输出:6
# add_integers(1, '2', 3)  # 抛出 TypeError: 所有参数必须是整数

2. 缓存函数结果(Memoization)

示例:

def memoize(fn):
    cache = {}
    def wrapper(*args):
        if args in cache:
            return cache[args]
        result = fn(*args)
        cache[args] = result
        return result
    return wrapper

@memoize
def fibonacci(n):
    if n <= 2:
        return 1
    return fibonacci(n-1) + fibonacci(n-2)

print(fibonacci(10))  # 输出:55

3. 统一接口的API设计

设计可接受各种参数的API,提高灵活性。

示例:

def api_request(endpoint, *args, **kwargs):
    url = f"https://api.example.com/{endpoint}"
    print(f"请求URL:{url}")
    print(f"位置参数:{args}")
    print(f"关键字参数:{kwargs}")
    # 这里可以添加实际的请求逻辑

api_request('get-data', 1, 2, key='value', token='abcd1234')
# 输出:
# 请求URL:https://api.example.com/get-data
# 位置参数:(1, 2)
# 关键字参数:{'key': 'value', 'token': 'abcd1234'}

八、总结

灵活性: *args和**kwargs使函数能够接受可变数量和类型的参数,增加了函数的灵活性。

代码复用: 在装饰器和高阶函数中使用,能编写更加通用的代码。

注意事项: 使用时要注意参数的顺序和解包的正确性,避免参数冲突。

通过深入理解和灵活运用*args和**kwargs,我们可以编写出更加高效、灵活的Python代码。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2138182.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【JavaScript】数据结构之树

什么是树形结构&#xff1f; 一种分层数据的抽象模型&#xff0c;用来分层级关系的。虚拟dom它所组织的那个数据原理就是树形结构 深度优先搜索&#xff08;遍历&#xff09;- 递归 从根出发&#xff0c;尽可能深的搜索树的节点技巧 访问根节点对根节点的children挨个进行深…

三、(JS)JS中常见的表单事件

一、onfocus、onblur事件 这个很容易理解&#xff0c;就不解释啦。 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"&…

【JS|第27期】网页文件传输:Blob与Base64的对决

日期&#xff1a;2024年9月12日 作者&#xff1a;Commas 签名&#xff1a;(ง •_•)ง 积跬步以致千里,积小流以成江海…… 注释&#xff1a;如果您觉得有所帮助&#xff0c;帮忙点个赞&#xff0c;也可以关注我&#xff0c;我们一起成长&#xff1b;如果有不对的地方&#xf…

【SQL】百题计划:SQL最基本的判断和查询。

[SQL]百题计划 Select product_id from Products where low_fats "Y" and recyclable "Y";

java重点学习-JVM组成

十二 JVM 12.1 JVM运行原理 Java Virtual Machine Java程序的运行环境(java二进制字节码的运行环境) 好处: 一次编写&#xff0c;到处运行自动内存管理&#xff0c;垃圾回收机制 12.2 什么是程序计数器? 程序计数器:线程私有的&#xff08;不存在线程安全问题&#xff09;&…

美团图床设置教程

大厂图床&#xff0c;CDN加速 项目地址&#xff1a;https://github.com/woniu336/mt-img 使用方法 在mt.php填上你的token即可&#xff0c;然后打开index.html上传图片 获取token方法 注册https://czz.meituan.com/发布视频&#xff0c;上传封面&#xff0c;注意在上传封面后…

java项目之企业级工位管理系统源码(springboot)

项目简介 企业级工位管理系统实现了以下功能&#xff1a; 企业级工位管理系统的主要使用者管理员功能有个人中心&#xff0c;部门信息管理&#xff0c;工位信息管理&#xff0c;使用情况管理&#xff0c;工位分配管理。员工可以查看个人中心&#xff0c;部门信息&#xff0c;…

linux第二课(docker的安装使用)

目录 一.关于docker (1)背景引入 (2)docker介绍 (3)功能 (4)Docker架构 二.docker的安装及相关的命令 (1)docker的安装 (2)docker的配置 (3)docker镜像命令 (4)容器命令 三.docker安装myaql ​编辑 四.数据卷挂载 1.数据卷挂载引入 2.数据卷挂载图解 3.数据卷的安装…

通用四期ARM架构银河麒麟桌面操作系统V10【安装、配置FTP服务端】

一、操作环境 服务端&#xff1a;银河麒麟桌面操作系统V10SP1 &#xff08;服务端包链接&#xff1a;https://download.csdn.net/download/AirIT/89747026&#xff09; 客户端&#xff1a;银河麒麟桌面操作系统V10SP1 &#xff08;客户端包链接&#xff1a;https://downloa…

List<Map<String, Object>>汇总统计排序

开发环境&#xff1a;jdk 1.8 需求一&#xff1a; 1、统计每个小时(升序)不同事件的产品产量 2、统计不同事件&#xff08;OK 、NG&#xff09;的总产量 public static void main(String[] args) {//数据源List<Map<String, Object>> list new ArrayList<Map…

微信小程序开发第三课

1 wxml语法 1.1 模版语法 # 1 在页面 xx.js 的 Page() 方法的 data 对象中进行声明定义 # 2 在xx.wxml 中使用 {{}} 包裹&#xff0c;显示数据 # 3 可以显示如下&#xff0c;不能编写js语句或js方法-变量-算数运算-三元运算-逻辑判断# 4 只是单纯通过赋值&#xff0c;js中…

[Python学习日记-22] Python 中的字符编码(下)

[Python学习日记-22] Python 中的字符编码&#xff08;下&#xff09; 简介 编码的战国时代 Unicode 和 UTF 现代计算机系统通用的字符编码工作方式 简介 在[Python学习日记-21] Python 中的字符编码&#xff08;上&#xff09;中我们讲了字符编码中的 ASCII 码和 GB2312/G…

算法刷题:300. 最长递增子序列、674. 最长连续递增序列、718. 最长重复子数组、1143. 最长公共子序列

300. 最长递增子序列 1.dp定义&#xff1a;dp[i]表示i之前包括i的以nums[i]结尾的最长递增子序列的长度 2.递推公式&#xff1a;if (nums[i] > nums[j]) dp[i] max(dp[i], dp[j] 1); 注意这里不是要dp[i] 与 dp[j] 1进行比较&#xff0c;而是我们要取dp[j] 1的最大值…

【前端】ref引用的作用

首先&#xff0c;我们要明确一点&#xff0c;使用vue的好处是&#xff1a; 想要减少开发者直接操作dom元素。使用组件模版&#xff0c;实现代码的服用。 ref的属性的实现是为了取代原生js中使用id、class等标识来获取dom元素。 helloworld组件 <template><div clas…

memset函数的使用

目录 1.头文件 2.memset函数讲解 小心&#xff01;VS2022不可直接接触&#xff0c;否则&#xff01;没这个必要&#xff0c;方源面色淡然一把抓住&#xff01;顷刻炼化&#xff01; 1.头文件 memset函数的使用需要包括头文件 #include<string.h> 2.memset函数讲解 简述…

Java--图书管理系统(新版详细讲解)

前言&#xff1a; 对于初学者&#xff0c;自己写一个图书管理系统&#xff0c;会有效提高自己的代码能力&#xff0c;加深对Java中面向对象的理解&#xff0c;里面蕴含了Java中的类、接口、继承、多态等思想&#xff0c;接下来我们一起完成这一份"伟大的作品!" 注&am…

【若依RuoYi-Vue | 项目实战】帝可得后台管理系统(一)

文章目录 一、项目背景介绍1、什么是帝可得&#xff1f;2、物联网3、售货机术语4、角色与功能5、业务流程&#xff08;1&#xff09;平台管理员&#xff08;2&#xff09;运维人员&#xff08;3&#xff09;运营人员&#xff08;4&#xff09;消费者 6、产品原型7、库表设计 二…

基于Web的《药谷奇遇记》网站设计与实现---附源码72940

目 录 1 绪论 1.1 研究背景与意义 1.2国内外研究现状 1.3论文结构与章节安排 2 系统分析 2.1 可行性分析 2.1.1 技术可行性分析 2.1.2 经济可行性分析 2.1.3 法律可行性分析 2.2 系统功能分析 2.2.1 功能性分析 2.2.2 非功能性分析 2.3 系统用例分析 2.4 系统流程…

18062 二维数组每行中的最大值

### 思路 1. 使用指针变量遍历二维数组的每一行。 2. 对于每一行&#xff0c;找到该行的最大值。 3. 输出每一行的最大值。 ### 伪代码 1. 定义一个指向二维数组的指针变量 p。 2. 遍历二维数组的每一行&#xff1a; - 将 p 指向当前行。 - 初始化 max 为当前行的第一个…

【STM32系统】基于STM32设计的SD卡数据读取与上位机显示系统(SDIO接口驱动、雷龙SD卡)——文末资料下载

基于STM32设计的SD卡数据读取与上位机显示系统 演示视频&#xff1a; 基于STM32设计的SD卡数据读取与上位机显示系统 简介&#xff1a;本研究的主要目的是基于STM32F103微控制器&#xff0c;设计一个能够读取SD卡数据并显示到上位机的系统。SD卡的数据扇区读取不仅是为了验证存…