文章目录
- 第3章:函数
Effective Python——编写高质量Python代码的90个有效方法
本书介绍:https://effectivepython.com/
代码demo:https://effectivepython.com/
第3章:函数
第23条 用关键字参数来传参
位置传递参数
与大多数其他编程语言一样,Python允许在调用函数时,按照位置传递参数(也就是按照参数列表所指定的顺序依次传递参数)。
def remainder(number, divisor):
return number % divisor
assert remainder(20, 7) == 6
关键字传递参数
Python函数里面的所有普通参数,除了按位置传递外,还可以按关键字传递。
调用函数时,在调用括号内可以把关键字的名称写在=
左边,把参数值写在右边。
这种写法不在乎参数的顺序,只要把必须指定的所有位置参数全都传过去即可。
位置和关键字传递参数混合使用
另外,关键字形式与位置形式也可以混用。下面这四种写法的效果相同:
如果混用,那么位置参数必须出现在关键字参数之前,否则就会出错。
每个参数只能指定一次,不能既通过位置形式指定,又通过关键字形式指定。
通过字典解包**my_kwargs
传参
如果有一份字典,而且字典里面的内容能够用来调用remainder 这样的函数,那么可以把 **
运算符加在字典前面,这会让 Python 把字典里面的键值以关键字参数的形式传给函数。
调用函数时,带 **
操作符的参数可以和位置参数或关键字参数混用,只要不重复指定就行。
也可以对多个字典分别施加**
操作,只要这些字典所提供的参数不重叠就好。
(这不就是参数解包吗?参考文章:Python 运算符(pythonkwargs:参数解包)(kwargs:keyword arguments))
函数定义万能形参**kwargs
定义函数时,如果想让这个函数接受任意数量的关键字参数,那么可以在参数列表里写上万能形参**kwargs
,它会把调用者传进来的参数收集合到一个字典里面稍后处理。
(第26条讲了一种特别适合这么做的情况)。
def print_parameters(**kwargs):
for key, value in kwargs.items():
print(f'{key} = {value}')
print_parameters(alpha=1.5, beta=9, gamma=4)
print('*'*50)
my_kwargs = {
'number': 2,
'divisor': 7
}
print_parameters(**my_kwargs)
关键字参数好处
关键字参数的灵活用法可以带来三个好处。
第一个好处是,用关键字参数调用函数可以让初次阅读代码的人更容易看懂。
例如,读到remainder(20,7)这样的调用代码,就不太容易看出谁是被除数number,谁是除数divisor,只有去查看remainder的具体实现方法才能明白。
但如果改用关键字形式来调用,例如remainder(number=20,divisor=7),那么每个参数的含义就相当明了。
关键字参数的第二个好处是,它可以带有默认值,该值是在定义函数时指定的。
在大多数情况下,调用者只需要沿用这个值就好,但有时也可以明确指定自己想要传的值。这样能够减少重复代码,让程序看上去干净一些。
例如,我们要计算液体流入容器的速率。
如果这个容器带刻度,那么可以取前后两个时间点的刻度差(weight_diff),并把它跟这两个时间点的时间差(time_diff)相除,就可以算出流速了。
一般来说,我们会用每秒的千克数表示流速。
但有的时候,我们还想估算更长的时间段(例如几小时或几天)内的流速结果。
只需给同一个函数加一个period参数来表示那个时间段相当于多少秒即可。
这段代码中,period 参数使得函数可以根据用户定义的时间周期来调整流量计算。例如,如果想知道每小时的流量,可以将 period 设置为3600(秒数),这样就能得到小时平均流量。
这样写有个问题,就是每次调用函数时,都得明确指定period参数。即便我们想计算每秒钟的流速,也还是得明确指定period为1。
为了简化这种用法,我们可以给period参数设定默认值。
这样的话,period就变成可选参数了。
这个办法适用于默认值比较简单的情况。如果默认值本身要根据比较复杂的逻辑来确定(可参考第24条),那就得仔细考虑一下了。
关键字参数的第三个好处是,我们可以很灵活地扩充函数的参数,而不用担心会影响原有的函数调用代码。(有助于维护向后兼容)★★★★★
这样的话,我们就可以通过这些新参数在函数里面实现许多新的功能,同时又无须修改早前写好的调用代码,这也让程序不容易因此出现bug。
例如,我们想继续扩充上述flow_rate函数的功能,让它可以用千克之外的其他重量单位来计算流速。那只需要再添加一个可选参数,用来表示1千克相当于多少个那样的单位即可。
通过引入 units_per_kg 参数,进一步增加了 flow_rate 函数的灵活性。这个参数是用于将重量差异转换成其他单位,例如流体体积或者化学物质的摩尔数。这样做的目的是为了使函数更通用,可以适用于不同类型的流量计算。
units_per_kg 参数用于将重量(公斤)转换成其他单位。例如,如果你在测量水的流量,而设备提供的数据是以公斤为单位,你可能想要转换成升(L)。对于水,大约1公斤水等于1升。如果你想要计算每小时流过的升数,你可以将 units_per_kg 设置为1(表示1公斤水等于1升)。
新参数 units_per_kg的默认值为1,这表示默认情况下,依然以千克为重量单位来计算。
于是,以前写好的那些调用代码就不用修改了。
以后调用flow_rate 时,可以通过关键字形式给这个参数指定值,以表示他们想用的那种单位(例如磅,1千克约等于2.2磅)。
可选的关键字参数有助于维护向后兼容(backward compatibility)。
这是个相当重要的问题,对于接受带 *args
参数的函数,也要注意向后兼容(参见第22条)。
像 period 和 units_per_kg这样可选的关键字参数,只有一个缺点,就是调用者仍然能够按照位置来指定。
通过位置来指定可选参数,可能会让读代码的人有点儿糊涂,因为他不太清楚3600和2.2这两个值分别指哪个量的缩放系数。
所以,最好是能以关键字的形式给这些参数传值而不要按位置去传。从设计函数的角度来说,还可以考虑用更加明确的方案以降低出错概率(参见第25条)。
要点
函数的参数可以按位置指定,也可以用关键字的形式指定
关键字可以让每个参数的作用更加明了,因为在调用函数时只按位置指定参数,可能导致这些参数的含义不够明确。
应该通过带默认值的关键字参数来扩展函数的行为,因为这不会影响原有的函数调用代码。
可选的关键字参数总是应该通过参数名来传递,而不应按位置传递。
在Python中,当我们谈论“可选的关键字参数总是应该通过参数名来传递,而不应按位置传递”时,我们是在强调代码的可读性和稳健性。关键字参数(Keyword arguments)是那些在函数调用时通过参数名明确指定的参数。这种方式的主要优点包括:
1. 提高代码可读性
使用关键字参数可以使函数调用更加明确和易于理解。例如,考虑以下函数定义和调用:
def register(name, age, is_student=False):
pass
# 使用关键字参数调用
register(name="Alice", age=22, is_student=True)
在这个例子中,即使不查看 register
函数的实现,我们也能清楚地知道每个参数的意图和作用。对比如果按位置传递参数:
register("Alice", 22, True)
这里,True
的含义不够明确,除非查看函数定义。
2. 减少错误
当函数有多个参数,特别是多个可选参数时,使用关键字传递参数可以减少因位置错误导致的bug。例如:
def create_window(title, width=800, height=600, border=True, resizable=False):
pass
# 使用关键字参数调用
create_window(title="My App", resizable=True, height=500)
通过关键字指定,我们可以安全地跳过某些默认参数,直接提供其他需要修改的参数,避免了位置错误。
3. 允许更灵活的函数签名变动
使用关键字参数的另一个好处是,当函数的参数列表在未来发生变化时,调用代码不太可能因此而中断。如果增加、删除或更改参数的默认值,使用关键字参数的函数调用通常不需要修改。
4. 强制关键字参数
在Python中,函数定义可以通过在参数前加 *
(如 def func(*, key1, key2): pass
)来强制使某些参数必须使用关键字参数形式传递。这种做法在函数接受多个参数或参数含义不明显时特别有用,有助于避免混淆和错误。
综上所述,通过参数名传递关键字参数是一种好的编程实践,它不仅使代码更清晰、安全,而且还提高了代码的灵活性和未来的可维护性。
Python函数的位置参数(position argument)与关键字参数(keyword argument)概念,默认参数值
在Python中,函数参数可以通过两种主要方式传递:位置参数和关键字参数。了解这两种类型的参数及其使用方式是掌握Python函数的关键部分。
位置参数
位置参数是最常见的参数类型,它们需要按照在函数定义中指定的顺序传递。例如,如果一个函数定义如下:
def func(a, b, c):
print(a, b, c)
在调用func
时,你必须按照a
, b
, c
的顺序提供三个参数:
func(1, 2, 3) # 输出: 1 2 3
如果参数的顺序或数量错误,Python将抛出错误。
关键字参数
关键字参数允许你在调用函数时指定参数名,这样参数的顺序就可以任意了。继续使用上面的例子,使用关键字参数的方式如下:
func(a=1, c=3, b=2) # 输出: 1 2 3
这里,即使参数的顺序与定义中的不同,只要指明了参数名,函数依然可以正确地接收到所有的值。
混合使用位置参数和关键字参数(所有的位置参数必须位于任何关键字参数之前)
当你混合使用位置参数和关键字参数时,所有的位置参数必须位于任何关键字参数之前。例如:
func(1, b=2, c=3) # 正确
但是,如下的调用将会导致错误:
func(b=2, 1, c=3) # 错误,位置参数1不应该在关键字参数b之后
默认参数值
关键字参数常与默认参数值一起使用,这让函数调用更加灵活。例如:
def func(a, b=2, c=3):
print(a, b, c)
在这个例子中,b
和c
都有默认值,所以在调用时可以省略它们:
func(1) # 输出: 1 2 3
func(1, c=4) # 输出: 1 2 4
通过这种方式,可以根据需要只提供部分参数,其余参数使用定义时的默认值。
“关键字参数”跟“可选参数”不是同一回事!(可选参数是针对函数定义而言,关键字参数是针对函数调用而言)
关键字参数(keyword arguments)和可选参数(optional parameters)是两个相关但有区别的概念,在Python编程中经常被使用,但它们的含义并不完全相同:
关键字参数 (Keyword Arguments)
关键字参数指的是在函数调用时,通过参数名明确指定的参数。这意味着,无论参数在函数定义中的位置如何,都可以通过指定参数名称来传递参数值。关键字参数增加了代码的可读性和灵活性。
例如:
def print_details(name, age):
print(f"Name: {name}, Age: {age}")
# 使用关键字参数调用
print_details(name="Alice", age=30)
在上述调用中,name
和 age
是通过关键字来指定的,它们是关键字参数。
可选参数 (Optional Parameters)
可选参数通常指的是在函数定义中通过为参数提供默认值来实现的参数。这意味着在调用函数时,可以选择不传递这些参数,函数会自动使用定义时给出的默认值。这类参数对于提供默认行为或设置非必需的配置很有用。
例如:
def log_message(level, message, timestamp=True):
if timestamp:
print(f"[{time.ctime()}] {level}: {message}")
else:
print(f"{level}: {message}")
# 可以选择不传递 timestamp 参数
log_message("INFO", "This is a log message.")
在上述定义中,timestamp
是一个可选参数,因为它有一个默认值 True
。
关系和区别
- 关键字参数可以是可选的也可以是必需的。关键字参数的关键特性在于,参数是通过名称指定的,而不是通过位置。
- 可选参数通常是通过为参数提供默认值来实现的,它们可以通过位置或关键字方式传递。
虽然可选参数往往是通过关键字传递(特别是当存在多个可选参数时),但它们不必总是关键字参数。可选参数的“可选”特性来自于它们有默认值,而关键字参数的特性是它们通过名称来指定。
标签:传参,函数,位置,指定,关键字,参数,默认值 From: https://blog.csdn.net/Dontla/article/details/139809651