惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

T
Tor Project blog
AI
AI
S
Securelist
P
Privacy International News Feed
A
Arctic Wolf
T
Tenable Blog
C
Cisco Blogs
P
Proofpoint News Feed
Application and Cybersecurity Blog
Application and Cybersecurity Blog
Google Online Security Blog
Google Online Security Blog
S
Schneier on Security
AWS News Blog
AWS News Blog
L
Lohrmann on Cybersecurity
D
Darknet – Hacking Tools, Hacker News & Cyber Security
N
News and Events Feed by Topic
Know Your Adversary
Know Your Adversary
H
Heimdal Security Blog
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Cyberwarzone
Cyberwarzone
C
Cybersecurity and Infrastructure Security Agency CISA
S
Security Affairs
P
Palo Alto Networks Blog
K
Kaspersky official blog
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
博客园 - 叶小钗
Recent Commits to openclaw:main
Recent Commits to openclaw:main
博客园 - Franky
SecWiki News
SecWiki News
IT之家
IT之家
G
GRAHAM CLULEY
酷 壳 – CoolShell
酷 壳 – CoolShell
C
CERT Recently Published Vulnerability Notes
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
L
LINUX DO - 最新话题
宝玉的分享
宝玉的分享
月光博客
月光博客
H
Help Net Security
P
Proofpoint News Feed
Cloudbric
Cloudbric
Latest news
Latest news
Spread Privacy
Spread Privacy
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Schneier on Security
Schneier on Security
Help Net Security
Help Net Security
Apple Machine Learning Research
Apple Machine Learning Research
Webroot Blog
Webroot Blog
B
Blog
量子位
J
Java Code Geeks
MyScale Blog
MyScale Blog

晚花行乐

马克卡尼在2026年达沃斯论坛上的讲话(阅读材料) | 晚花行乐 鸡娃如何用力才是恰到好处 | 晚花行乐 读万卷书,行万里路的辩证关系 | 晚花行乐 反对培训机构掐尖招生 | 晚花行乐 小泽和建国会谈最后10分钟全文(阅读材料) | 晚花行乐 来看看 DeepSeek 怎么鸡娃 | 晚花行乐 谈谈基本功 | 晚花行乐 惠普 ProDesk SFF PC 各系列参数对比 | 晚花行乐 解决瘦客户机上安装 Debian 12 启动失败问题 | 晚花行乐 意拾喻言:老外写的文言文 | 晚花行乐 笠翁对韵中的典故(十三元) | 晚花行乐 谈谈中考取消四小门 | 晚花行乐 亚马逊云科技产品免费试用攻略(3) - 对象存储服务 | 晚花行乐 在 Windows 10 LTSC 版本上安装 WSL2 | 晚花行乐 Debian 12 的常用配置项 | 晚花行乐 在 Debian 12 上安装 Nvidia 显卡驱动程序 | 晚花行乐 解决 Debian 12 关机失败问题 | 晚花行乐 解决 VS Code 自动更新版本后卡在连接界面 | 晚花行乐 观看巴黎奥运会有感 | 晚花行乐 在 Windows10 上安装惠普旧打印机驱动程序 | 晚花行乐 欢迎关注公众号:晚花行乐 | 晚花行乐 如何编写拼写检查器 | 晚花行乐 亚马逊云科技产品免费试用攻略(2) - 云服务器 | 晚花行乐 Pandas 中 axis 参数的理解(附实例) | 晚花行乐 我打算命个名,叫什么什么 Manager | 晚花行乐 上海武康路历史建筑一览 | 晚花行乐 Python 实现简单的数学表达式解析并处理 | 晚花行乐 观看马拉松的感悟 | 晚花行乐 Python 保存 Cookies 到文件并再次读取 | 晚花行乐 如何为 Hugo 静态网站添加评论功能 | 晚花行乐 Linux 共享打印服务 CUPS | 晚花行乐 如何为 Hugo 静态网站添加搜索功能 | 晚花行乐 解决 CSV 文件的第一列不能解析 | 晚花行乐 亚马逊云科技产品免费试用攻略(1) - 注册账户 | 晚花行乐 第二幕 Atma 的闲聊 | 晚花行乐 第二幕野蛮人的语音 | 晚花行乐 古入声和普通话平声对照 | 晚花行乐 第一幕的背景音乐 | 晚花行乐 第二幕亚马逊的语音 | 晚花行乐 第一幕的亚马逊的语音 | 晚花行乐 第一幕的野蛮人的语音 | 晚花行乐 MacOS 的彩蛋:Here's to the crazy ones | 晚花行乐 笠翁对韵的基本知识 | 晚花行乐 笠翁对韵中的典故(十二文) | 晚花行乐 笠翁对韵中的典故(十一真) | 晚花行乐 笠翁对韵中的典故(十灰) | 晚花行乐 杭州景点的楹联 | 晚花行乐 adb keycode 大全 | 晚花行乐 Scikit-learn 学习笔记(0)名词术语 | 晚花行乐 Scikit-learn 学习笔记(3)监督学习的例子 | 晚花行乐 SQLite 文档的学习笔记(1)长期支持计划 | 晚花行乐 SQLite 文档的学习笔记(2)测试方法 | 晚花行乐 笠翁对韵中的典故(九佳) | 晚花行乐 Ansible 如何检查一个程序的版本 | 晚花行乐 Ansible 如何检查一个文件夹是否存在 | 晚花行乐 pip 配置文件详解 | 晚花行乐 Ansible 如何检查一个URL是否正常 | 晚花行乐 Ansible 如何修改 iptables 规则 | 晚花行乐 Ansible 指定 playbook 运行的主机 | 晚花行乐 Ansible 如何清空文件夹 | 晚花行乐 Ansible 如何在本机执行命令 | 晚花行乐 笠翁对韵中的典故(八齐) | 晚花行乐 Python 中 Defaultdict 的理解 | 晚花行乐 《伊索寓言》电子书 | 晚花行乐 菲伯尔钢琴伴奏:第二册 | 晚花行乐 Python 的 Keyword-Only Arguments 理解 | 晚花行乐 瓦瑞夫在第一幕的闲聊 | 晚花行乐 瓦瑞夫在第一幕的任务提示 | 晚花行乐 第一幕的女巫语音 | 晚花行乐 《Fluent Python》 读书笔记:文本和字节序列 | 晚花行乐 第一幕的罗格语音 | 晚花行乐 第一幕的圣骑士语音 | 晚花行乐 第一幕的男巫语音 | 晚花行乐 第一幕的旁白 | 晚花行乐 第一幕的恶魔 | 晚花行乐 Python 中 Element Tree 的理解 | 晚花行乐 《Fluent Python》 读书笔记:字典和集合 | 晚花行乐 笠翁对韵中的典故(七虞) | 晚花行乐 笠翁对韵中的典故(五微) | 晚花行乐 笠翁对韵中的典故(六鱼) | 晚花行乐 笠翁对韵中的典故(一东) | 晚花行乐 笠翁对韵中的典故(二冬) | 晚花行乐 笠翁对韵中的典故(三江) | 晚花行乐 笠翁对韵中的典故(四支) | 晚花行乐 姜太公钓鱼 | 晚花行乐 武王建立周朝 | 晚花行乐 大禹治水 | 晚花行乐 尧舜让位 | 晚花行乐 黄帝战蚩尤 | 晚花行乐 上下五千年-精简版 | 晚花行乐 成功修复鼠标按键 | 晚花行乐 横向的Word文档怎么加页眉页脚 | 晚花行乐 商标通用化的故事:商标代替商品名 | 晚花行乐 搜索空文件夹的批处理程序 | 晚花行乐 Sn0wbreeze不能运行? | 晚花行乐 天线的驻波比 | 晚花行乐 天线参数:增益Gain | 晚花行乐 天线参数:方向图Radiation pattern | 晚花行乐 本拉登别墅的Google Earth坐标 | 晚花行乐 宜家帕克斯(PAX)衣柜的拼装过程 | 晚花行乐
Python 的 函数参数处理机制 | 晚花行乐
2022-01-05 · via 晚花行乐

本文综述 Python 函数的参数类型和捕获过程。parameter 的作用是捕获 argument,又叫做 参数处理机制(parameter handling mechanism),本文的主题围绕这一个捕获过程。

parameter 和 argument 的区别

这篇文章 ,解释了 parameter 和 argument 的概念上的区别。

parameter 出现在函数定义中;argument 出现在函数调用中。

可以用下面的例子解释:

# 定义
def f(a):
    pass

# 调用
f(1)

这个例子中,定义函数时的 a 是 parameter, 而调用函数时的 1 是 argument.

参数的捕获

当函数被调用的时候,如何让用户提供的 argument 被正确的赋值给 parameter, 是从 argument 到 parameter 的映射。

因为这个映射是个从左往右的有序的动作,所以更形象的说,是一个:

  • parameters 捕获 arguments 的过程
  • argument values 填入 parameter slots 的过程

parameter 列表形成一个个的 slot,而 argument 包含若干个 value,通过一系列规定好的逻辑,将 value 捕获到 slot 中去,这就是参数处理机制(parameter handling mechanism),本文的主题围绕这一个捕获过程,系统的梳理一下参数处理机制。

通过位置捕获

最简单的捕获方式就是通过位置捕获,这和 shell 函数相同:

# 定义
def f(a, b):
    pass

# 调用
f(1, 2)

这里的 ab 靠自身所处的位置捕获参数值,称为 Positional arguments. 这种通过位置对应获取参数的方式可以称为

  • 隐式(implicit)的获取
  • 匿名参数

参数值会按照位置一一对应到参数列表中的变量中去。如果提供的参数列表个数和定义的不符合,无论多还是少,都会抛出 TypeError

>>> def f(a,b):
...     pass
...
>>> f(1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: f() missing 1 required positional argument: 'b'
>>> f(1,2,3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: f() takes 2 positional arguments but 3 were given
>>>

位置参数的困难

当参数列表很长时,会遇到一个困难,就是需要逐个参数对应。比如

>>> def f(a,b,c,d,e,f,g):
...     pass
...
>>> f(1,2,3,4,5,6,7)
>>>

如果想修改中间某个参数,需要先到参数列表中从左向右数出来参数的位置:

------>
f(a,b,c,d,e,f,g)

然后再到 arguments 列表里从左到右数出来参数的位置。

------>
f(1,2,3,4,5,6,7)

这种定位参数的方式会让人很累,造成可读性差、易出错。在隐式获取基础上,需要一种显示的获取(explicit capture),也就是赋值时指定变量名称。

通过名称捕获

名称捕获又叫关键字参数,Keyword arguments. 通过变量名直接指定参数值。

举个例子:

>>> def f(a,b,c,d,e,f,g):
...     pass
...
>>> f(1,2,3,4,5,6,7)
>>> f(g=1,f=2,e=3,d=4,c=5,b=6,a=7)
>>>

如果要修改某个参数值,可以方便的找到参数名称。

关键字参数的优点是能通过变量名称了解参数值的含义,提高了可读性。

位置参数和关键字参数的混合

当有些参数以 位置参数形式提供,有些参数以 关键字参数 形式提供时,会遇到新问题:

如果 keyword argument 放置于 positional argument 前面,会抛出 SyntaxError ,因为如果列表前面提供了参数名称后,后面的参数就不能根据位置捕获。

举个例子:

>>> def f(a,b,c,d,e,f,g):
...     pass
...
>>> f(g=1,f=2,3,4,5,b=6,a=7)
  File "<stdin>", line 1
    f(g=1,f=2,3,4,5,b=6,a=7)
                           ^
SyntaxError: positional argument follows keyword argument
>>>

比如上面的例子里,参数值3就很难说希望被哪个参数捕获。所以得到一条原则:

原则1:

调用函数时,位置参数必须先于关键字参数提供。

基于这个原则,在设计函数时,需要把希望关键字参数放在参数列表后面。

位置参数关键字参数 两种参数属于简单的类型,合称 positional-or-keyword arguments

参数默认值

定义函数时,参数列表里可以为参数提供默认值,提供了默认值的参数是可选的,不具备默认值的参数是必选的。

因为可选参数有可能不提供,如果可选参数后面出现必选参数,就会出现混淆。

>>> def f(a,b=1,c):
  File "<stdin>", line 1
    def f(a,b=1,c):
                 ^
SyntaxError: non-default argument follows default argument
>>>

上面的例子里,如果调用函数

f(1, 2)

就难以确定 2 是应该被 b 还是 c 捕获。

所以得到一条原则:

原则2:

定义函数时,必选参数必须先于可选参数提供。

可变长度位置参数

有一种情形,是不能预知 位置参数 的数量,比如 max() 函数:

>>> max('a')
'a'
>>> max('a','b','c')
'c'
>>>

使用 varargs 语法(*号,starred expression)将多个位置参数收集在一起,放入一个 parameter 中,这个 parameter 在函数内部作为一个 tuple 存在。

>>> def f(*a):
...     print(a)
...
>>> f(1,2,3,4)
(1, 2, 3, 4)
>>>

可以理解为:参数 a 前的星号将参数列表 (1,2,3,4) 收集在一起,合成一个 tuple, 赋值给变量a。这个过程叫 packing.

在定义函数时,参数名前的星号表示 packing;在调用函数时,参数名前的星号表示 unpacking:

>>> def f(*a):
...     print(a)
...
>>> b='123'
>>> f(*b)
('1', '2', '3')
>>>

可变长度关键字参数

可变长度位置参数 类似,不能预知长度的 关键字参数 也可以用一个变量收集在一起,区别在于收集的结果不是 tuple 而是 dict, 而且使用两个星号。

>>> def f(**a):
...     print(a)
...
>>> f(b=1, c=2)
{'b': 1, 'c': 2}
>>>

一样可以 unpacking

>>> f(**{'b':1,'c':2})
{'b': 1, 'c': 2}
>>>

注意参数名在字典中是以字符串形式存在。这个例子有个额外的好处:有些情况下,变量名不能方便的写在函数参数列表里(比如参数名里有空格),解决方法就是用 unpacking:

>>> def f(**a):
...     for k,v in a.items():
...         print(k,v,sep='->')
...
>>> f(**{'b d':1,'c':2})
b d->1
c->2
>>>

4种参数的两两组合

上面介绍了4种参数:

这4种参数存在4种两两组合场景,前两个参数的组合场景已经在 这一节 讨论。下面我们仔细观察另外3种场景下的参数定义。

普通位置参数 和 可变长度位置参数的组合

有这么一种场景,一些参数是固定的,另一些参数是不固定长度的,这样可以混合两种参数用法:

比如人的名字和携带的物品:

>>> def f(name, *inventory):
...     print(name+': '+', '.join(inventory))
...
>>> f('Amy','water','food')
Amy: water, food
>>> f('Bob','car')
Bob: car
>>>

由于 packing 是将右边所有位置参数都收集在一起,所以带星号的参数不能出现在在普通的位置参数之前,比如(*a, b),不然后面的参数就会被收集进去。

在 Python 2.x 的时代,(*a, b) 这么定义函数是不合法的:

# Python 2.x
>>> def f(*a, b):
  File "<stdin>", line 1
    def f(*a, b):
              ^
SyntaxError: invalid syntax
>>>

在 Python 3.x 的时代,虽然允许了这种写法,但是*号表达式右边的参数必须以关键字形式提供,也就是(*a, b)中的b,这称为 Keyword-Only Arguments,另开一篇文章叙述。

普通位置参数 和 可变长度关键字参数的混合

类似上面一节的内容,

可以写出下面的函数定义:

>>> def f(name, **inventory):
...     print(name+': '+', '.join([k+': '+v for k,v in inventory.items()]))
...
>>> f('Amy', food='bread', juice='apple')
Amy: food: bread, juice: apple
>>> f('Bob', car='jeep')
Bob: car: jeep
>>>

不允许普通位置参数写在 packing关键字参数后面:

将抛出 SyntaxError

>>> def f(**inventory, name):
  File "<stdin>", line 1
    def f(**inventory, name):
                       ^
SyntaxError: invalid syntax
>>>

可变长度位置参数 和 可变长度关键字参数的混合

如果 位置参数数量和关键字参数数量都不能预知,那么就需要组合两种参数:

>>> def f(*names, **inventory):
...     print(', '.join(names)+': '+', '.join([k+': '+v for k,v in inventory.items()]))
...
>>> f('Amy','Bob', car='jeep')
Amy, Bob: car: jeep
>>> f('Cindy', 'David',food='bread', juice='apple')
Cindy, David: food: bread, juice: apple
>>>

这一节相同的理由,可变长度位置参数 不能放在 可变长度关键字参数后面:

>>> def f(**inventory, *names):
  File "<stdin>", line 1
    def f(**inventory, *names):
                       ^
SyntaxError: invalid syntax
>>>

结论

上面对 Python 函数的参数定义做了一番综述,概括下来有三类参数和三项原则:

三类参数

还有另外两种参数,在各自单独文章内介绍,分别是:

合计 五类参数

三项原则

位置参数

  • 调用函数时,位置参数必须先于关键字参数提供。
  • 定义函数时,必选参数必须先于可选参数提供。
  • 定义函数时,普通的位置参数必须先于可变长度参数提供。

各位读后有什么想法,请在下方留言吧!如果对本文有疑问或者寻求合作,欢迎 联系邮箱邮箱已到剪贴板

精彩评论