14、Python之super star:一颗星、两颗星,满天都是小星星

引言

关于Python系列的文章,已经通过两篇文章,介绍了Python中关于函数的简单使用,包括为什么要使用函数,以及函数中带默认值参数的使用注意事项。

之后,岔开函数的主题,通过几篇番外篇,重点谈了一下Python中一切皆对象、Python的数据模型,以及Python中函数和类也是一等公民的理念。其实,关于函数也一直有所涉及。

今天,准备结合Python中星号(star)操作符的用法,继续展开Python中函数的介绍。

关于星号(*)的使用,主要内容有:

1、基础的乘法运算
2、字符串的重复
3、列表的扩充
4、定义不定长的函数位置参数
5、函数调用时,将列表拆包为位置参数进行传递
6、定义不定长的函数关键字参数
7、函数调用时,将字典拆包为关键字参数进行传递

python中的乘法运算

*号是所有编程语言中,比较常见的操作符,首先能够想到的就是四则运算中的乘法运算。没错,首次接触编程语言的新手,可能在键盘上找不到表示乘法运算的x。在所有编程语言中,都是使用*的。

# *的基础作用,乘法运算:
a = 10
b = 5
print(f"{a}乘以{b}的结果是:{a * b}")

# Python中也支持复合赋值的操作:
# 等价于 b = b * 100
b *= 100
print(b)

执行结果:

除了数字可以进行乘法运算,Python中将乘法运算进行了扩充:
字符串可以与数字进行相乘,进行字符串的重复

# 书读百遍,其义自现;百遍太多,十遍也行
s1 = 'Life is short, I use Pyton\n'
s2 = s1 * 10
print(s2)

执行结果:

列表也可以进行乘法运算的扩充:

# 一个不过瘾,我要打十个
enemies = ['小喽啰']
print(id(enemies))
enemies *= 10
print(id(enemies))
print(enemies)

执行结果:


这里的复合赋值操作,实际上进行了原列表对象的扩充,而非重新构造一个列表对象。

自动打包

在前面的文章中,介绍Python的unpacking机制时,已经用到过*号,将不需要的元素进行装包,这里简单回顾一下:

# * unpacking
persons = [('张三', 18, 190, '女'), ('小红', 23, 165, '男')]
for p in persons:
    name, *others, gender = p
    print(others)
    print(type(others))
    print(f"姓名: {name}, 性别: {gender}")


还是,之前的代码,我们通过*号修饰others变量,从而将除了name、gender接收的元素外,统一打包为一个列表,交由others变量来进行接收:

函数中的位置参数

相较于其他编程语言中的函数调用,形参列表和实参列表必须一一对应,按顺序传递(默认值参数除外)。Python中将必须按照顺序一一传递的函数调用传参,称为位置参数:

a = 10
b = 5
result = divide(a, b)
print(f"{a}除以{b}的结果是:{result}")

我们很容易碰到的一个问题是,如何定义一个函数,可以接收不定数目的参数,比如以下实际场景:
我们如何定义一个函数,可以计算若干个数字的和?
在其他编程语言中,可以通过函数重载来实现,可以定义多个同名的函数,但是参数列表的参数类型、个数不同。
但是,Python中似乎不支持函数重载。

很容易想到的一个变通的解法是我们定义一个接收一个列表作为参数的函数,列表中有几个元素,就是对几个元素求和:

# 定义一个接收列表的函数,从而变通地实现不定数目的参数求和
def my_sum(args):
    result = 0
    for num in args:
        result += num
    return result


nums = [1, 2, 3, 4, 5]
print(my_sum(nums))

这样,确实能够实现不定长参数的问题,但是,每次调用函数,都必须包装成一个列表,然后才能进行传参,似乎有点不太方便。

不定长位置参数

其实,Python中有更好的解决方案:通过*号,让函数接收数量可变的位置参数,可以让函数的设计、使用更加清晰。

这些位置参数通常简称为varargs,或者叫作star args,因为在Python中,我们习惯于使用*args来进行数量可变的位置参数的定义(注意,只是习惯,可以是别的命名方式)。

接下来,还是关于数字求和的问题,我们看star args的函数定义方式:

# 定义star args的函数,实现不定数目的参数求和
def my_sum(*args):
    result = 0
    for num in args:
        result += num
    return result


# 函数调用
print(my_sum(1, 2, 3, 4, 5))

可以发现,只需要将原来的函数定义的地方,参数前面加个*就可以解决这个问题了。

函数的调用方式,变成了直接传具体的数字就行了,有多少传多少,不需要包装成列表对象了。

如果由于历史原因,已经将参数包装成列表了,怎么办呢,也可以通过调用时加*进行unpacking处理:

# 定义star args的函数,实现不定数目的参数求和
def my_sum(*args):
    result = 0
    for num in args:
        result += num
    return result


# 列表调用
nums = [1, 2, 3, 4, 5]
print(my_sum(*nums))

不定长的star args,也可以跟固定的位置参数混合使用:

# 定义star args的函数,实现不定数目的参数求和
def my_sum(initial_value, *args):
    result = initial_value
    for num in args:
        result += num
    return result


# 列表调用
nums = [1, 2, 3, 4, 5]
print(my_sum(100, *nums))

有些教材中,描述说固定的位置参数必须放在star args之前进行定义,这种说法其实是不严谨的。

这两种参数,可以理解为一个是必选的参数,另一个是可选的参数。由于都是按照位置来传,就没法区分,哪个是由必选参数接收,哪个又是由可选参数接收了。

Python中,通过关键字参数机制来避免位置参数传参的二义性。

函数中的关键字参数

由于通过位置参数进行传参,必须顺序一一对应,稍不留神,可能就会导致错误,而且后续函数扩展,增加新的位置参数,所有调用的地方都要按照顺序调整……

好在Python中除了位置参数的函数调用方式,还可以通过关键字进行传参,可以避免位置错乱的问题,回到前面的除法的函数:

# 简单的关键字参数调用演示
def divide(a, b):
    return a / b


# 我们都一样
print(divide(10, 5))
print(divide(10, b=5))
print(divide(a=10, b=5))
print(divide(b=5, a=10))

回到上面关于数量不定的位置参数,并不是star args后面,就不能定义必选参数了,只是调用时需要使用关键字参数进行调用而已。

所以,Python中关于函数参数定义的规定是:在star args之后定义的参数,都是关键字参数,调用的时候,只能使用关键字参数的方式进行参数传递:

# 定义star args的函数,实现不定数目的参数求和
def my_sum(*args, initial_value):
    result = initial_value
    for num in args:
        result += num
    return result


# 列表调用
nums = [1, 2, 3, 4, 5]
# 这种定义方式会报错,可以清晰地看到不定长位置参数与关键字参数混用的限制
print(my_sum(*nums, 100))

运行报错:


必须以关键字参数的形式传递initial_value这个参数。正确的调用方式:

print(my_sum(*nums, initial_value=100))
print(my_sum(initial_value=100, *nums))

从Python 3.8开始,哪怕函数不需要不定长的位置参数,也可以在函数定义中,使用*号,来强制要求之后的参数必须作为关键字参数进行传参:

# Python3.8开始的,*使用

def star_func(a, b, *, c, d):
    print(f"a: {a}, b: {b}, c: {c}, d:{d}")


# 报错 TypeError: star_func() takes 2 positional arguments but 4 were given
# star_func(1, 2, 3, 4)

# 报错 TypeError: star_func() missing 2 required keyword-only arguments: 'c' and 'd'
# star_func(1, 2)

# 正确调用方式:
star_func(1, 2, d=10, c=5)

不定长关键字参数

位置参数可以不定数目,实现函数的一次定义,灵活调用。关键字参数,其实也是可以的。这就是要介绍的两颗星的使用了(**)

在Python函数定义中的两个习惯:

  • *args:进行不定长的位置参数的定义
  • **kwargs:进行不定长的关键字参数的定义

再次说明,只是习惯,args、kwargs的参数名是可以随意的。

以一个简单的示例说明下不定长关键字参数的定义:

def double_star_func(**kwargs):
    print("传递的关键字参数有:")
    for key, value in kwargs.items():
        print(f"key: {key}, value: {value}")


double_star_func(a=1, b=2, c='hello python')
double_star_func(host='127.0.0.1', port=3306, user='deploy', database='test')

此外,如同我们可以通过列表来进行位置参数的传递,关键字参数,我们可以通过字典对象进行传递。

通过将我们已有的存储在字典中的配置信息,以关键字参数的方式进行传递,可以极大地简化函数的调用。

比如,有如下场景,我们需要进行MySQL的数据库连接,我们以字典对象的方式存储了多个数据库的连接配置信息:

第一种连接数据库的函数调用方式:

import pymysql

db_configs = {
    'dev': {
        'host': '127.0.0.01',
        'port': 3306,
        'user': 'dev_user',
        'password': 'dev_password',
        'database': 'db_dev'
    },
    'test': {
        'host': '127.0.0.01',
        'port': 3306,
        'user': 'test_user',
        'password': 'test_password',
        'database': 'db_test'
    },
    'prod': {
        'host': '127.0.0.01',
        'port': 3306,
        'user': 'prod_user',
        'password': 'prod_password',
        'database': 'db_prod'
    }
}

dev_db = db_configs['dev']
db_conn = pymysql.connect(host=dev_db['host'], port=dev_db['port'], user=dev_db['user'], password=dev_db['password'], database=dev_db['database'])


有点麻烦……
第二种连接方式:我们看是用字典传参的方式:

import pymysql

db_configs = {
    'dev': {
        'host': '127.0.0.01',
        'port': 3306,
        'user': 'dev_user',
        'password': 'dev_password',
        'database': 'db_dev'
    },
    'test': {
        'host': '127.0.0.01',
        'port': 3306,
        'user': 'test_user',
        'password': 'test_password',
        'database': 'db_test'
    },
    'prod': {
        'host': '127.0.0.01',
        'port': 3306,
        'user': 'prod_user',
        'password': 'prod_password',
        'database': 'db_prod'
    }
}

db_conn = pymysql.connect(**db_configs['dev'])

在函数调用时,可以通过两个星号(**)来将字典解析为函数的关键字参数进行传递,从而简化函数的调用。

总结

在Python中,星号(*)的主要用法有:

1、基础的乘法运算
2、字符串的重复
3、列表的扩充
4、定义不定长的函数位置参数
5、函数调用时,将列表拆包为位置参数进行传递
6、定义不定长的函数关键字参数
7、函数调用时,将字典拆包为关键字参数进行传递

只要理解了这几点,在后续的使用中,就能大大简化自己代码的编写,真正提高代码的编写效率,毕竟我们选择用Python的原因在于人生苦短。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

什么是边缘计算技术和边缘计算平台?

随着物联网、5G技术和人工智能的不断发展,数据的规模和种类也在快速增加。在这种背景下,传统的云计算模式面临着一些问题,例如延迟高、网络拥塞等,这些问题限制了数据的处理速度和效率,降低了用户的使用体验。为了解决…

Zookeeper之CAP理论及分布式一致性算法

CAP理论 CAP理论告诉我们,一个分布式系统不可能同时满足以下三种 一致性(C:consistency)可用性(A:Available)分区容错性(P:Partition Tolerance) 这三个基本要求,最多只能同时满足…

ZGC的流程图

GC标记过程 1、初始标记 扫描所有线程栈的根节点,然后再扫描根节点直接引用的对象并进行标记。这个阶段需要停顿所有的应用线程(STW),但由于只扫描根对象直接引用的对象,所以停顿时间很短。停顿时间高度依赖根节点的数…

Redis的使用(四)常见使用场景-缓存使用技巧

1.绪论 redis本质上就是一个缓存框架,所以我们需要研究如何使用redis来缓存数据,并且如何解决缓存中的常见问题,缓存穿透,缓存击穿,缓存雪崩,以及如何来解决缓存一致性问题。 2.缓存的优缺点 2.1 缓存的…

JMeter进行HTTP接口测试的技术要点

参数化 用户定义的变量 用的时候 ${名字} 用户参数 在参数列表中传递 并且也是${} csv数据文件设置 false 不忽略首行 要首行 从第一行读取 true 忽略首行 从第二行开始 请求时的参数设置: 这里的名称是看其接口需要的请求参数的名称 这里的变量名称就是为csv里面…

SpringBatch文件读写ItemWriter,ItemReader使用详解

SpringBatch文件读写ItemWriter,ItemReader使用详解 1. ItemReaders 和 ItemWriters1.1. ItemReader1.2. ItemWriter1.3. ItemProcessor 2.FlatFileItemReader 和 FlatFileItemWriter2.1.平面文件2.1.1. FieldSet 2.2. FlatFileItemReader2.3. FlatFileItemWriter 3…

低空经济持续发热,无人机培训考证就业市场及前景剖析

随着科技的不断进步和社会需求的日益增长,低空经济已成为全球及我国经济增长的新引擎。作为低空经济的重要组成部分,无人机技术因其广泛的应用领域和显著的经济效益,受到了社会各界的广泛关注。为满足市场对无人机人才的需求,无人…

【动态规划1】斐波那契数列模型篇

文章目录 声明动态规划介绍1137.第N个泰波那契数题目描述分析代码 面试题 08.01. 三步问题题目描述分析代码 746.使用最小花费爬楼梯题目描述分析代码 91.解码⽅法题目描述分析代码 声明 本篇博客为动态规的基础篇,从零开始学习动态规划,如有错误&#…

MATLAB quiver矢量图 设置colorbar

给三维矢量图按照不同高度设置箭头颜色 figure clf X surfaceuz(:,1); Y surfaceuz(:,2); Z surfaceuz(:,3); hold onzcolor jet; % qquiver3(X,Y,Z,X,Y,W) for i 1:length(surfaceuz)quiver3(X(i),Y(i),Z(i),X(i),Y(i), Z(i),...Color,zcolor(floor((Z(i) - -0.1) * 2…

408数据结构-图的应用3-有向无环图、拓扑排序 自学知识点整理

前置知识:表达式,图的遍历 有向无环图描述表达式 有向无环图:若一个有向图中不存在环,则称为有向无环图,简称 D A G DAG DAG图 。 (图片来自王道考研408数据结构2025) 由王道考研-咸鱼学长的讲…

深圳晶彩智能JC3636W518C开箱实现电脑副屏功能

深圳晶彩智能发布了JC3636W518C 这是一款中国制造的,铝合金外壳,价格非常震撼的开发板。原创是billbill的up播主萨纳兰的黄昏设计的ESP32太极小派,由深圳晶彩智能批量生产。 该款 LCD 模块采用 ESP32-S3R8 芯片作为主控,该主控是双核 MCU&…

Vulnhub:DC-1

1.环境搭建 靶机下载地址 将下载的靶机导入到Oracle VM VirtualBox中,设置仅主机模式,使用和kali相同的网卡 2.渗透过程 使用nmap工具进行主机发现扫描 nmap -sn 192.168.56.0/24 发现靶机ip地址,使用nmap工具进行靶机端口扫描 nmap -sS…

一文说透Springboot单元测试

你好,我是柳岸花开。 一、单元测试说明 1 单元测试的优点与基本原则 一个好的单元测试应该具备以下FIRST 原则和AIR原则中的任何一条: 单元测试的FIRST 规则 Fast 快速原则,测试的速度要比较快, Independent 独立原则,…

Qt 多窗体、复用窗口的使用

1.继承自QWidge的窗口的呈现,作为tabPage呈现,作为独立窗口呈现 2.继承自QMainWindow的窗口的呈现,作为abPage呈现,作为独立窗口呈现 1. 继承自QWidge的窗口的呈现 1.1 作为tabPage呈现 void MutiWindowExample::on_actWidgetI…

AI绘画入门实践|Midjourney 提示词的使用技巧

提示词长短 尽可能做到简洁明了。 提示词很短 MJ 出图的随机性更高,创造的内容更有想象力,更适合创意发散的图像生成。 a dog 提示词很长 MJ 出图会更加精准,但描述太过详细,有可能出现AI理解不到位的情况。 越到后面的提示词&…

风险评估:IIS的安全配置,IIS安全基线检查加固

「作者简介」:冬奥会网络安全中国代表队,CSDN Top100,就职奇安信多年,以实战工作为基础著作 《网络安全自学教程》,适合基础薄弱的同学系统化的学习网络安全,用最短的时间掌握最核心的技术。 这一章节我们需…

Java面试八股之Redis集群Cluster

Redis集群Cluster Redis Cluster是一种基于数据分片(Sharding)的分布式缓存和存储系统,它实现了数据的水平扩展、高可用性和自动故障转移。以下是对Redis Cluster模式详细实现流程的描述: 1. 初始化与配置 部署节点&#xff1a…

flutter 手写 TabBar

前言: 这几天在使用 flutter TabBar 的时候 我们的设计给我提了一个需求: 如下 Tabbar 第一个元素 左对齐,试了下TabBar 的配置,无法实现这个需求,他的 配置是针对所有元素的。而且 这个 TabBar 下面的 滑块在移动的时…

产品经理-产品经理会在项目中遇到的几个问题(16)

项目中遇到了需求变更怎么办? 首先要弄清楚需求变更的原因是什么。如果是因为在迭代的过程中更好地理解了用户需求 进而产生了更好的需求则完全是正常的。如果是因为老板的需求 那就需要和老板沟通清楚,并且确保自己能理解老板的需求,而且这个…

软件测试——测试用例

工作职责: 1.负责产品系统测试,包括功能测试、性能测试、稳定性测试、用户场景测试、可靠性测试等。 2.负责测试相关文档的编写,包括测试计划、测试用例、测试报告等。 3.负责自动化测试框架、用例的维护。 岗位要求: 1.熟练…