1.问题
想定义一个函数或者方法,其中一个或者多个参数是可选的并且带有默认值
2.解决方案
表面上定义一个带有可选默认参数的函数时非常简单的
In [1]: def func(a, b =1):
...: return a + b
...:
In [2]: func(1)
Out[2]: 2
In [3]: func(1,2)
Out[3]: 3
但如果默认值时可变容器的话,比如果列表、集合或者字典等,那么应该把None作为默认值。
代码如下:
In [4]: def func(a, b = None):
...: if b is None:
...: b = []
如果不打算提供一个默认值,只是想编写代码来检测可选参数否被赋予了某个特定的值,那么可以采用下面的惯用手法
In [5]: _no_value = object()
In [6]: def func(a, b = _no_value):
...: if b is _no_value:
...: print("No b value supplied")
In [7]: func(1)
No b value supplied
In [8]: func(1,2) # b = 2
In [9]: func(1,None) # b = None
# 请仔细区分不传递任何值和传递None之间的额区别
3.总结
给默认参数赋值的应该总是不可变的对象,比如None、True、False、数字或者字符串等。特别注意的是,绝对不要编写下面这样的代码
如果默认值在函数体外被修改了,那么这种修改将在之后的函数调用后对参数的默认值产生持续的影响
In [1]: def func(a, b =[]):
...: return b
...:
In [2]: x = func(1)
In [3]: x
Out[3]: []
In [4]: x.append(1)
In [5]: x.append("A")
In [6]: x
Out[6]: [1, 'A']
In [7]: func(1) # 返回了之前修改的列表
Out[7]: [1, 'A']
这可能是很多人不期待的结果,要避免这种问题,最好使用解决方案中的做法,使用None作为默认值,并在函数体中曾家岩一个队默认值的检查
当检测默认值是否为None的时候,关键之处在于对is操作符的运用,有时候可能会犯下面这样的错误
In [1]: def func(a, b =None):
...: if b == None:
...: b = []
...:
但是这里的问题在于,尽管None会被检测为False,但是还有其他许多的对象(比如空字符串、空列表、空元组、空字典)也会被检测为False,因此这种方法不可取
在函数检测视为可选参数提供了某个特定值(可以是任意值),这里最为棘手的是我们不能用None、0、Fasle当做默认自来检测用户是否提供了参数(因为这些值都是完全合法的参数,用户极有可能把他们当做参数)。要解决这个问题,可以利用object()来创建一个独特的私有实例,在函数中可以用这个特殊值来同用户提供的参数做相等性测试,以此判断是否输入了参数。
In [5]: object
Out[5]: object
In [6]: object()
Out[6]: <object at 0x6318f40>
这里用到的object()可能看起来很不常见.object作为Python中几乎所有对象的基类而存在.可以穿件object的实例,但是他没有任何值得注意的方法,也没有任何实例数据(因为底层缺少__dict__方法,我们甚至没有办法为他设置任何属性)。唯一可做的就是检测相等性,这也使得他可以作为特殊值来使用。
本文探讨了在Python中定义带有默认参数的函数时遇到的问题,特别是当默认值是可变容器如列表、集合或字典时。建议使用None作为默认值,并在函数内部检查。总结强调,不应直接在函数外部修改默认值,以免影响后续调用。推荐使用is操作符来检测None,避免误判其他假值。最后,提出用object()创建独特实例来检测用户是否提供了参数,以避免与合法参数混淆。

3087

被折叠的 条评论
为什么被折叠?



