最近在通过廖雪峰的Python学习网站重新系统性地学习Python语言。看到函数-函数的参数-默认参数时,我对廖老师”默认参数的坑“中的怪象感到疑惑,虽然廖老师进行了解释,但是我还是没有完全能理解,现在参考了其他大佬的解释,将我的理解记录如下。
首先复述一下问题:
先定义一个函数,传入一个list,添加一个END再返回:

def add_end(L=[]):L.append('END')return L

当你正常调用时,结果似乎不错:

>>> add_end([1, 2, 3])
[1, 2, 3, 'END']
>>> add_end(['x', 'y', 'z'])
['x', 'y', 'z', 'END']

当你使用默认参数调用时,一开始结果也是对的:

>>> add_end()
['END']

但是,再次调用add_end()时,结果就不对了:

>>> add_end()
['END', 'END']
>>> add_end()
['END', 'END', 'END']

很多初学者很疑惑,默认参数是[],但是函数似乎每次都“记住了”上次添加了END后的list。

原因解释如下:
L=[]在Python中实质上是将变量L指向了列表[],或者更进一步说,列表存储于“堆”中,变量存储于“栈”中,变量L记录了列表[]的地址。
正常来说,函数结束后L是具有退栈的步骤的,即释放变量L内存储的地址。但是默认参数只在函数定义的时候计算一次,将其地址传递给变量L。后面调用的时候不再将新的地址传递给L。所以L存储的永远是同一个地址。每一次调用add_end()函数,列表中就会多一个'END'。由于L指向的永远是原有列表,就会导致上述现象。
因此Python的函数涉及到默认参数时,必须选取不可变对象。
要修改上面的例子,我们可以用None这个不变对象来实现:

def add_end(L=None):if L is None:L = []L.append('END')return L

现在,无论调用多少次,都不会有问题:

>>> add_end()
['END']
>>> add_end()
['END']

这一修正方法的原理可以解释如下:
None是不变对象,L=[][]现在不是默认参数,每次调用时,都会重新计算列表[]在堆中的地址,将其赋值给L。需要注意的是,[]['END']的地址是不一样的,因为重新计算过。
贴一篇:
python中赋值与c语言区别

廖雪峰Python学习相关推荐

  1. 廖雪峰python学习笔记之高级特性

    写在前面 寒假时本科舍友的一句话点醒梦中人-你的python基础还没弄明白吧!猛地一想好像确实如此,还停留在随插随用的程度,并且对于迭代器,函数式编程等等,没有深刻理解,所以项目做起来也是空中楼阁,所 ...

  2. 廖雪峰Python学习笔记1

    Python基础 文章目录 一.基础语法规范 二.数据类型 三.字符串与编码 四.条件判断 五.循环 一.基础语法规范 1.用#作为代码注释 2.当语句以冒号:结尾时,缩进的语句视为到麻花,缩进**使 ...

  3. 【廖雪峰Python学习笔记】错误、调试、测试

    文章目录 错误处理 调试 单元测试unitcase 文档测试 错误类型 程序编写问题bug – 字符类型错误等 用户输入错误 – 输入不符合规定的字符串 异常,程序运行时无法预测 – 磁盘满了,无法写 ...

  4. 【廖雪峰Python学习笔记】面向对象编程OOP

    面向对象编程 OOP:Object Oriented Programming 程序的基本单元:对象 [ = 数据 + 操作数据的函数] [属性 + 方法] 三大特点:数据封装.继承和多态 OPP中的计 ...

  5. 【廖雪峰Python学习笔记】函数式编程

    Functional Programming 高阶函数 返回函数 匿名函数 装饰器 偏函数 高阶函数 面向过程的程序设计: 把大段代码拆成函数,通过一层层函数调用,可将复杂任务分解成若干简单的任务 函 ...

  6. 【廖雪峰Python学习笔记】list tuple dict set

    列表 元组 字典 集合 创建 l = [1, 'a', [1, 3], True] t = (1, ) d = {'key' : 'value'} s = set([1, 2, 4, 2, 1]) 索 ...

  7. 【廖雪峰Python学习笔记】字符串与编码

    字符串与编码 三种字符编码 ASCII编码 :计算机由美国人发明,最早只有127个字符编码-- 大小写英文字母.数字和符号 Unicode:把中文.日文.韩文等所有语言统一到一套编码中,2-4byte ...

  8. 廖雪峰Python学习笔记——类和实例

    Class MyList(list): __metaclass__ = ListMetaclass #它表示在创建MyList这个类时,必须通过 ListMetaclass这个元类的LIstMetac ...

  9. 廖雪峰python学习笔记——函数式编程

    一个简单粗暴的内置函数: reduce()和map()的区别: map()是将函数依次作用到每个参数上,而reduce()相当于是迭代,而且每次都必须是两个参数. 用reduce()和map完成str ...

  10. 廖雪峰Python学习笔记2

    Python基础 文章目录 一.定义函数 二.函数参数 三.递归函数 一.定义函数 格式:定义一个函数要使用def语句,依次写出函数名.括号.括号中的参数和冒号:,然后,在缩进块中编写函数体,函数的返 ...

最新文章

  1. 为什么密码比字符串更喜欢char []?
  2. iOS 11开发教程(一)
  3. android 去掉蓝牙传输文件功能_iPhone还在用蓝牙传输照片?这个功能更好用还快哟,了解一下...
  4. JS 获取控件的绝对位置
  5. java 指针_java多线程学习二十二:::java中的指针
  6. 30个让人兴奋的视差滚动(Parallax Scrolling)效果网站
  7. nginx作为tcp代理 虚拟主机配置 模板
  8. 一个还算简单的微信消息SDK(基于.Net Standard 2.0)
  9. linux c之fdopen(int fd, const char *type)使用总结
  10. Flex DataGrid 筛选实现
  11. snm算法_基于SNM算法的大数据量中文地址清洗方法
  12. 电子计算机审计,计算机审计存在的风险
  13. 查询水果价格c语言程序框图,浙大版《C语言程序设计(第3版)》题目集 练习3-8 查询水果价格 (15 分)...
  14. 在HBuilder里为什么输入汉字是繁体字,而我的输入法设置的是简体
  15. Pytest如何并发执行自动化脚本
  16. Lightning Network模拟器
  17. 高德LBS开放平台携手SAE 抱团背后开发者受益
  18. 硬核科普:什么是狭义相对论?它有哪些惊人结论?
  19. android开发 实现动态获得app的cpu占有率并导出文件的两种方法。
  20. Java-------类、继承、重载

热门文章

  1. POI设置背景色采坑记录
  2. [GO语言基础] 一.为什么我要学习Golang以及GO语言入门普及
  3. LAMP使开放源代码软件安全性提高
  4. vissim4.3安装教程
  5. 开源mysql客户端_14款经典的MySQL客户端软件
  6. Jmeter压力测试实战
  7. 离散傅里叶变换MATLAB实现
  8. 设置eclipse主题风格
  9. 国军标GJB150可靠性试验检测服务第三方检测机构报告
  10. 【区块链】区块链技术指南