在Fluent Python一书第八章有一个示例,未看书以先很难理解这个示例运行的结果,我们先看结果,然后再分析问题原因:

定义了如下Bus类:

 class Bus:
def __init__(self, passengers=[]):
self.passengers = passengers def pick(self, name):
self.passengers.append(name) def drop(self, name):
self.passengers.remove(name)

创建两个Bus 类实例,bus1, bus2

>>> import Example8_12
>>> bus1 = Example8_12.Bus()
>>> bus2 = Example8_12.Bus()

假如bus1接到一个一名乘客Alice:

>>> bus1.pick('Alice')

此时我们看看bus2里的乘客:

>>> bus2.passengers
['Alice']

bus2本应该是空的,但是此时却有bus1 pick的乘客'Alice', 这是什么原因呢?

出现这个问题的根源是:默认值在定义函数时计算(通常是在import 模块时),并且默认值变成了函数对象的属性:

我们可以省察下类Bus __init__方法的属性

>>> dir(Example8_12.Bus.__init__)
['__annotations__', '__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__get__', '__getattribute__', '__globals__', '__gt__', '__hash__', '__init__', '__kwdefaults__', '__le__', '__lt__', '__module__', '__name__', '__ne__', '__new__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']

留意其中有个__defaults__属性,我们看看其中的内容:

>>> Example8_12.Bus.__init__.__defaults__
(['Alice'],)

我们可以看到'Alice'正在其中,这也是为什么bus2里会有乘客'Alice'的原因.

我们可以验证bus2.passengers是一个别名,它绑定到Bus1.__init__.__defaults__属性的第一个元素上了:

>>> Example8_12.Bus.__init__.__defaults__[0] is bus2.passengers
True

这个示例说明了为什么通常使用None作为接收可变值的参数的默认值。

这个类正确的书写应该如下:

 class Bus:
def __init__(self, passengers=None):
if passengers is None:
self.passengers = []
else:
self.passengers = list(passengers) def pick(self, name):
self.passengers.append(name) def drop(self, name):
self.passengers.remove(name)

这里有一个原则,如果定义的函数接收可变参数,应该谨慎考虑调用方是否期望修改传入的参数。

Fluent Python: Mutable Types as Parameter Defaults: Bad Idea的更多相关文章

  1. 学习笔记之Fluent Python

    Fluent Python by Luciano Ramalho https://learning.oreilly.com/library/view/fluent-python/97814919462 ...

  2. 「Fluent Python」今年最佳技术书籍

    Fluent Python 读书手记 Python数据模型:特殊方法用来给整个语言模型特殊使用,一致性体现.如:__len__, __getitem__ AOP: zope.inteface 列表推导 ...

  3. Fluent Python: memoryview

    关于Python的memoryview内置类,搜索国内网站相关博客后发现对其解释都很简单, 我觉得学习一个新的知识点一般都要弄清楚两点: 1, 什么时候使用?(也就是能解决什么问题) 2,如何使用? ...

  4. python的types模块

    python的types模块 1.types是什么: types模块中包含python中各种常见的数据类型,如IntType(整型),FloatType(浮点型)等等. >>> im ...

  5. Python深入学习之《Fluent Python》 Part 1

    Python深入学习之<Fluent Python> Part 1 从上个周末开始看这本<流畅的蟒蛇>,技术是慢慢积累的,Python也是慢慢才能写得优雅(pythonic)的 ...

  6. Fluent Python: Classmethod vs Staticmethod

    Fluent Python一书9.4节比较了 Classmethod 和 Staticmethod 两个装饰器的区别: 给出的结论是一个非常有用(Classmethod), 一个不太有用(Static ...

  7. Fluent Python: @property

    Fluent Python 9.6节讲到hashable Class, 为了使Vector2d类可散列,有以下条件: (1)实现__hash__方法 (2)实现__eq__方法 (3)让Vector2 ...

  8. 《Fluent Python》---一个关于memoryview例子的理解过程

    近日,在阅读<Fluent Python>的第2.9.2节时,有一个关于内存视图的例子,当时看的一知半解,后来查了一些资料,现在总结一下,以备后续查询: 示例复述 添加了一些额外的代码,便 ...

  9. [Python] Pitfalls: About Default Parameter Values in Functions

    Today an interesting bug (pitfall) is found when I was trying debug someone's code. There is a funct ...

随机推荐

  1. acm--1004

    问题描述 再次比赛时间!看到气球在四周漂浮,多么兴奋.但要告诉你一个秘密,评委最喜欢的时间是猜测最流行的问题.比赛结束后,他们会统计每种颜色的气球并找出结果. 今年,他们决定离开这个可爱的工作给你. ...

  2. Linux 学习第五天

    一.重定向.管道符.通配符 1.重定向.管道符使用 重定向: 命令文件 管道符: 命令A:命令B  (管道符  |  别称 “任意门”) 二.常用命令 1.ls /etc | wc -l  (查看目录 ...

  3. canvas常用属性方法由浅下沉

    首先引入<canvas></canvas>标签就不必说了. 其次就是得到canvas的2d环境了( var ctx = canvasDom.getContext('2d') ) ...

  4. windows 10 安装node.js

    第一步:下载软件 nodejs的中文官网http://nodejs.cn/download/ 选择 windows  系统 msi 安装版本. 下载完成之后,直接打开下一步安装就可以. 安装完成 打开 ...

  5. 企业网站被黑 dedecms漏洞修复办法

    前段时间网站被黑了,从百度打开网站直接被劫持跳转到了彩票,du博网站上去,网站的首页index.html文件也被篡改成一些什么北京sai车,pk10,一些cai票的关键词内容,搞得网站根本无法正常浏览 ...

  6. Node.js的Formidable模块的使用,方便快捷

    服务用的是express ,如果不是很老的express框架,都有自带formidable  如果没有就下载一个  npm i formidable var formidable = require( ...

  7. MySQL入门第一天——概述、数据表与约束操作

    一.概述 1.安装 初学MySQL,我们下载msi的安装版:http://dev.mysql.com/downloads/file.php?id=457403 安装的过程文字简述可以参考之前随笔:ht ...

  8. 【调试】Linux下超强内存检测工具Valgrind

    [调试]Linux下超强内存检测工具Valgrind 内容简介 Valgrind是什么? Valgrind的使用 Valgrind详细教程 1. Valgrind是什么? Valgrind是一套Lin ...

  9. HTML5 离线应用程序

    离线Web应用:当客户端本地与Web应用程序的服务器没有建立连接时,也能正常在客户端本地使用该Web应用. Web应用程序的本地缓存与浏览器的网页缓存的区别 1. 本地缓存为整个Web应用程序服务,网 ...

  10. MongoDB-Ubuntu环境下安装

    1.在官网下载安装包,下载后为 mongodb-linux-x86_64-ubuntu1604-3.4.6.tgz 解压:tar -zxvf mongodb-linux-x86_64-ubuntu16 ...