Python学习笔记之7.5 - 定义有默认参数的函数》》》直接在函数定义中给参数指定一个默认值,默认参数的值应该是不可变的对象
问题:
你想定义一个函数或者方法,它的一个或多个参数是可选的并且有一个默认值。
解决方案:
定义一个有可选参数的函数是非常简单的,直接在函数定义中给参数指定一个默认值,并放到参数列表最后就行了。例如:
def spam(a, b=42):
print(a, b) spam(1) # Ok. a=1, b=42
spam(1, 2) # Ok. a=1, b=2
如果默认参数是一个可修改的容器比如一个列表、集合或者字典,可以使用None作为默认值,就像下面这样:
# Using a list as a default value
def spam(a, b=None):
if b is None:
b = []
...
如果你并不想提供一个默认值,而是想仅仅测试下某个默认参数是不是有传递进来,可以像下面这样写:
_no_value = object() def spam(a, b=_no_value):
if b is _no_value:
print('No b value supplied')
...
我们测试下这个函数:
>>> spam(1)
No b value supplied
>>> spam(1, 2) # b = 2
>>> spam(1, None) # b = None
>>>
仔细观察可以发现到传递一个None值和不传值两种情况是有差别的。
讨论:
定义带默认值参数的函数是很简单的,但绝不仅仅只是这个,还有一些东西在这里也深入讨论下。
首先,默认参数的值仅仅在函数定义的时候赋值一次。试着运行下面这个例子:
>>> x = 42
>>> def spam(a, b=x):
... print(a, b)
...
>>> spam(1)
1 42
>>> x = 23 # Has no effect
>>> spam(1)
1 42
>>>
注意到当我们改变x的值的时候对默认参数值并没有影响,这是因为在函数定义的时候就已经确定了它的默认值了。
其次,默认参数的值应该是不可变的对象,比如None、True、False、数字或字符串。特别的,千万不要像下面这样写代码:
def spam(a, b=[]): # NO!
...
如果你这么做了,当默认值在其他地方被修改后你将会遇到各种麻烦。这些修改会影响到下次调用这个函数时的默认值。比如:
>>> def spam(a, b=[]):
... print(b)
... return b
...
>>> x = spam(1)
>>> x
[]
>>> x.append(99)
>>> x.append('Yow!')
>>> x
[99, 'Yow!']
>>> spam(1) # Modified list gets returned!
[99, 'Yow!']
>>>
这种结果应该不是你想要的。为了避免这种情况的发生,最好是将默认值设为None,然后在函数里面检查它,前面的例子就是这样做的。
在测试None值时使用 is 操作符是很重要的,也是这种方案的关键点。有时候大家会犯下下面这样的错误:
def spam(a, b=None):
if not b: # NO! Use 'b is None' instead
b = []
...
这么写的问题在于尽管None值确实是被当成False,但是还有其他的对象(比如长度为0的字符串、列表、元组、字典等)都会被当做False。因此,上面的代码会误将一些其他输入也当成是没有输入。比如:
>>> spam(1) # OK
>>> x = []
# Silent error. x value overwritten by default 静默错误。 x值默认覆盖
>>> spam(1, x)
# Silent error. 0 ignored 静默错误。 0被忽略
>>> spam(1, 0)
# Silent error. '' ignored 静音错误。 ''忽略
>>> spam(1, '')
>>>
最后一个问题比较微妙,那就是一个函数需要测试某个可选参数是否被使用者传递进来。这时候需要小心的是你不能用某个默认值比如None、0或者False值来测试用户提供的值(因为这些值都是合法的值,是可能被用户传递进来的)。因此,你需要其他的解决方案了。
为了解决这个问题,你可以创建一个独一无二的私有对象实例,就像上面的_no_value变量那样。在函数里面,你可以通过检查被传递参数值跟这个实例是否一样来判断。这里的思路是用户不可能去传递这个_no_value实例作为输入。因此,这里通过检查这个值就能确定某个参数是否被传递进来了。
这里对 object() 的使用看上去有点不太常见。object 是python中所有类的基类。你可以创建 object 类的实例,但是这些实例没什么实际用处,因为它并没有任何有用的方法,也没有哦任何实例数据(因为它没有任何的实例字典,你甚至都不能设置任何属性值)。你唯一能做的就是测试同一性。这个刚好符合我的要求,因为我在函数中就只是需要一个同一性的测试而已。
Python学习笔记之7.5 - 定义有默认参数的函数》》》直接在函数定义中给参数指定一个默认值,默认参数的值应该是不可变的对象的更多相关文章
- Python学习笔记(二):条件控制语句与循环语句及常用函数的用法
总结的内容: 1.条件控制语句 2.while循环语句 3.for循环语句 4.函数的用法 一.条件控制语句 1.介绍 Python条件语句是通过一条或多条语句的执行结果(True或者False)来决 ...
- Python学习笔记(Django篇)——1、环境搭建篇(如何在Pycharm中配置Python和Django)
1.准备好以下东东,并且按照先后顺序进行安装: Python 3.6 (64-bit) Django-1.11.tar.gz pycharm-community-2016.3.2.exe 安装好了 ...
- python 学习笔记 12 -- 写一个脚本获取城市天气信息
近期在玩树莓派,前面写过一篇在树莓派上使用1602液晶显示屏,那么可以显示后最重要的就是显示什么的问题了. 最easy想到的就是显示时间啊,CPU利用率啊.IP地址之类的.那么我认为呢,假设可以显示当 ...
- Python字符串(Python学习笔记02)
字符串 Python 3 中的字符串可以使用双引号或单引号标示,如果字符串出现引号,则可以使用 \ 来去除引号标示字符串的作用. 几种字符串的表示方法: str1 = "hello" ...
- python学习笔记之module && package
个人总结: import module,module就是文件名,导入那个python文件 import package,package就是一个文件夹,导入的文件夹下有一个__init__.py的文件, ...
- OpenCV之Python学习笔记
OpenCV之Python学习笔记 直都在用Python+OpenCV做一些算法的原型.本来想留下发布一些文章的,可是整理一下就有点无奈了,都是写零散不成系统的小片段.现在看 到一本国外的新书< ...
- Python学习笔记(十三)
Python学习笔记(十三): 模块 包 if name == main 软件目录结构规范 作业-ATM+购物商城程序 1. 模块 1. 模块导入方法 import 语句 import module1 ...
- Python学习笔记(十一)
Python学习笔记(十一): 生成器,迭代器回顾 模块 作业-计算器 1. 生成器,迭代器回顾 1. 列表生成式:[x for x in range(10)] 2. 生成器 (generator o ...
- Python学习笔记(十)
Python学习笔记(十): 装饰器的应用 列表生成式 生成器 迭代器 模块:time,random 1. 装饰器的应用-登陆练习 login_status = False # 定义登陆状态 def ...
- Python学习笔记(九)
Python学习笔记(九): 装饰器(函数) 内置函数 1. 装饰器 1. 作用域 2. 高阶函数 3. 闭包 如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就 ...
随机推荐
- [记] OpenCV4 源码编译安装 | 记录
OpenCV4 源码编译安装 | 记录 参考资料 官方文档:https://docs.opencv.org/4.x/d7/d9f/tutorial_linux_install.html 环境 wsl2 ...
- .net core 序列日志Serilog
Serilog 是一个用于 .NET 应用程序的诊断日志库.它易于设置,具有干净的 API,并且可以在所有最新的 .NET 平台上运行.尽管即使在最简单的应用程序中它也很有用,但 Serilog 对结 ...
- 地址重写了,只是ip 没转发,应该是9999那个才对,rewrite /sbgl/(.*) http://127.0.0.1:9999/$1 permanent;,这样,
记录想nginx搞路径重写的失败历程. 1.想将从nginx发出的127.0.0.1:80 请求过来的带sbgl的字眼去掉,然后,代理为127.0.0.1:9999, 所以我就百度出这个 这个 r ...
- 【Java学习Day07】标识符
标识符 Java使用的组成部分的需要名字.类名.变量名以及方法名都被称为标识符 标识符的注意点 所有的标识符都应该以字母(A-Z或者a-z),美元符($).或者下划线(_)开始 首字符之后可以是字母( ...
- 查看oracle死锁
select A.sid, b.serial#, decode(A.type, 'MR', 'Media Recovery', 'RT','Redo Thread', 'UN','User Name' ...
- Java基础__04.GUI编程
GUI编程常见的组件: 窗口 弹窗 面板 文本框 列表框 按钮 图片 监听事件 鼠标操作 键盘事件 GUI简介 GUI的核心技术:Swing AWT,是需要jre环境的. AWT介绍 包含了很多类和接 ...
- k8s pod 抓包
首先安装tcpdump: yum install tcpdump kubectl get pod -o wide查看pod在哪个节点上 docker ps 查看container的id 查看pid: ...
- solt废弃,报错解决方法
1.饿了么组件库给出得文字提示框 写到项目里之后报错 提示 solt已经废弃 <el-tooltip placement="top"> <div slot=&qu ...
- ES深分页
一.背景 1.ES默认分页from+size 2.在大数据量和深度分页的时候,效率非常低 二.效率低原因 1.例如要查第501页的10条数据,from为5000,size为10 2.ES会查询并排序5 ...
- BIP 两个请求成功后,才能做某一件事
//保存前校验 let SetXStatus = 0; viewModel.on("beforeSave", function (args) { let _this = this; ...