笔者前面写了一篇关于Python函数定义中,使用“/”和“*”进行参数传递的介绍(Python效率秘籍:使用“*” 和“/” 让你的函数参数看起来更整洁)。有些朋友说是第一次见,有些朋友觉得跟自己之前的习惯混淆了,而有的朋友觉得更凌乱了,不知道其真正作用和使用场景。本文,我再次向大家说明一下这两种符号传参的作用和使用场景。Python专门将其加入到它的语言特性中,肯定自有它的用处和价值。
本文旨在向大家解释清楚两件事:
/ 的含义到底是什么?* 的含义到底是什么?理解这两个概念将有助于改善你的代码,提升性能,让你写出更简洁、优雅、易于维护和可读性更强的代码。
好啦,话不多说,我们直接上干货!
/ 和 * 用作运算符众所周知,这两个符号用作Python中的运算符时,分别表示数学操作中的除法和乘法运算。
def divide_by_n(m, n):
return m / n # divide m by n
def multiply_by_n(m, n):
return m * n # multiply m by n
用作运算符很容易理解,这里就不再赘述。
* 用法在函数定义中 * 有三种用法:
*args);**kwargs);前两种用法比较常见,如果有不清楚的可以看笔者之前写的文章(Python魔法参数:深入解析*args和**kwargs的强大用途):
但是,本文,我们主要关注的还是第三种用法——将 * 用作 仅限关键字 参数。定义为关键字参数,意味着我们需要通过参数名称来调用函数和传递形参。例如,
def func(employee_name: str, salary: float):
print(f'Employee Name: {employee_name}, Salary: {salary} $/m!')
这里,我们在函数中定义了两个参数——employee_name 和 salary。调用该函数时,既可以通过位置也可以通过关键字传递形参。但是为了避免值传递错误,最好通过关键字显式指定要将哪个值赋给哪个参数:
func(salary=6000, employee_name='Jack')
# Employee Name: Jack, Salary: 6000 $/m!
如你所见,使用关键字参数,我们可以用不同于函数定义时的参数顺序传递形参,且函数可以正常运行。
但是由于我们的函数可同时接受关键字参数和位置参数,如果我们使用位置参数调用函数的话可能会给参数传递错误的值:
func(6000, 'Jack')
# Employee Name: 6000, Salary: Jack $/m!
虽然函数也能正确运行,但是,很明显,参数的赋值完全错位了,将薪水赋给了员工姓名参数,而将姓名则赋给了薪水参数。这并不是我们期望的输出结果。
“那么我们该如何避免这种状况,从而确保正确地传递参数呢?
这个时候就需要我们将参数定义只接受关键字参数。这里就是 * 派上用场的时候了。只需要在参数列表中第一个 仅限关键字 形参前添加 * 即可:
def func(*, employee_name, salary):
print(f'Employee Name: {employee_name}, Salary: {salary} $/m!')
这样表示在调用函数时,* 后面的所有参数都必须通过关键字传递,否则解释器会报错:
正如你所见,第二种调用方式直接是语法错误,因为在关键字参数后面不能跟位置参数。而第三种调用方式则会发生类型错误,看报错信息就很明确,说该函数接受0个位置参数,但提供的是一个位置参数和一个仅限关键字参数。
在函数定义中使用 * 意味着在它之后的所有参数都只能通过关键字进行传递。而在 * 之前的参数都没有任何限制,位置参数和关键字参数都可以。例如,
def employee_info(message, *, employee_name, salary):
print(f'Message: {message}, Employee Name: {employee_name}, Salary: {salary} $/m!')
正如结果显示,* 前面的参数 message 既可以通过位置参数也可以通过关键字参数传递。
/ 用法继续我们的主题。在函数定义中,当我们将形参标记为 仅限位置 时,形参的顺序很重要,且这些形参不能用关键字传递。仅限位置形参应放在 / 前。/ 用于在逻辑上分割仅限位置形参与其它形参。
在某些特定场景下,必须使用 仅限位置 参数。比如,下面的函数定义中,kwds 把 name 当作键,因此,可能与位置参数 name 产生潜在冲突:
def foo(name, **kwargs):
return 'name' in kwargs
调用该函数不可能返回 True,因为关键字 'name' 总与第一个形参绑定。例如:
加上 / (仅限位置参数)后,就可以了。此时,函数定义把 name 当作位置参数,'name' 也可以作为关键字参数的键:
def foo(name, /, **kwargs):
return 'name' in kwargs
foo(1, **{'name': 2})
# True
换句话说,仅限位置形参的名称可以在 **kwds 中使用,而不产生歧义。
你可能会问为什么我们应该坚持使用仅限位置参数。有以下几点好处:
有一个名为 METH_FASTCALL 的方法,负责支持位置参数。根据 PEP570,这种方法专门为接受仅位置参数的函数服务。这个改进意味着减少了 Python 处理空关键字的成本。
其中一个原因是我们看到许多内置函数也是接受仅限位置的参数(例如 int、float 和 str),因为它们可以带来性能的提升。
使用仅限位置参数可以给我提供更多的灵活性,可以在无需担心出错的情况下修改参数名称。例如:
def func(first_name, last_name, /):
print(f'Hello, {first_name} {last_name}!')
func('Jack', 'Zhang')
# Hello, Jack Zhang!
# 修改参数名称
def func(f_name, l_name, /):
print(f'Hello, {f_name} {l_name}!')
func('Jack', 'Zhang')
# Hello, Jack Zhang!
如上所示,修改参数前后,并不会影响用户调用方式,前后使用同一种调用方法获得的结果都一样。
总之,请注意,/ 前面的形参表明只能使用位置参数传递,* 后面的形参则只能通过关键字参数传递,而二者中间的形参则不受限制。二者的作用和使用场景总结如下:
仅限位置参数:使用仅限位置形参,可以让用户无法使用形参名。形参名没有实际意义时,强制调用函数的实参顺序时,或同时接受位置形参和关键字时,这种方式很有用。
仅限关键字参数:当形参名有实际意义,且显式名称可以让函数定义更易理解时,阻止用户依赖传递实参的位置时,才使用关键字。
仅限位置参数:对于 API,使用仅限位置形参,可以防止未来修改形参名时造成破坏性的 API 变动。
感谢你的阅读,希望你能从中有所收获,提升自己的编码方式,助力自己成为更好的程序员!
圣人云,不积跬步,无以至千里;不积小流,无以成江海。希望每一个今天的你都变得比昨天更好!
推荐阅读👇👇👇
成为Python高手:掌握这5个核心技能,迈入编程精英行列!
Python魔法参数:深入解析*args和**kwargs的强大用途
Python高级技术:10个显著优化你代码的Python OOP 技术
Python技巧补给站:可以向你的同事炫耀的9个技巧,赶紧收藏起来~~
Python效率秘籍:使用“*” 和“/” 让你的函数参数看起来更整洁
- END -
“🌟 喜欢这篇文章吗?给个赞支持一下吧!🌟
如果你发现今天的内容对你有帮助,不妨点个赞并关注我,以便不错过更多关于Python、数据分析和机器学习的深入分析和最新趋势。我们一起探索数据的力量,解锁AI的潜能。您的每一次互动都是对我的极大鼓励,也是我们共同成长的动力!
“👇 关注并开启星标提醒,让知识与技能的火花不断在你的职业道路上燃烧吧!
原文作者:数据派探险家;如有侵权,请联系管理员删除。