不要使用可变类型作为参数的默认值

class HauntedBus:
"""备受幽灵乘客折磨的校车"""
def __init__(self, passengers=[]): ?
  self.passengers = passengers ?
def pick(self, name):
  self.passengers.append(name) ?
def drop(self, name):
  self.passengers.remove(name)

? 如果没传入 passengers 参数,使用默认绑定的列表对象,一开始 是空列表。

? 这个赋值语句把 self.passengers 变成 passengers 的别名,而没 有传入 passengers 参数时,后者又是默认列表的别名。

? 在 self.passengers 上调用 .remove() 和 .append() 方法时,修 改的其实是默认列表,它是函数对象的一个属性。

HauntedBus 的诡异行为如示例 8-13 所示。

>>> bus1 = HauntedBus([‘Alice‘, ‘Bill‘])
>>> bus1.passengers
[‘Alice‘, ‘Bill‘]
>>> bus1.pick(‘Charlie‘)
>>> bus1.drop(‘Alice‘)
>>> bus1.passengers ?
[‘Bill‘, ‘Charlie‘]
>>> bus2 = HauntedBus() ?
>>> bus2.pick(‘Carrie‘)
>>> bus2.passengers
[‘Carrie‘]
>>> bus3 = HauntedBus() ?
>>> bus3.passengers ?
[‘Carrie‘]
>>> bus3.pick(‘Dave‘)
>>> bus2.passengers ?
[‘Carrie‘, ‘Dave‘]
>>> bus2.passengers is bus3.passengers ?
True
>>> bus1.passengers ?
[‘Bill‘, ‘Charlie‘]

? 目前没什么问题,bus1 没有出现异常。

? 一开始,bus2 是空的,因此把默认的空列表赋值给 self.passengers。

? bus3 一开始也是空的,因此还是赋值默认的列表。

? 但是默认列表不为空!

? 登上 bus3 的 Dave 出现在 bus2 中。

? 问题是,bus2.passengers 和 bus3.passengers 指代同一个列 表。

? 但 bus1.passengers 是不同的列表。

表。 这种问题很难发现。如示例 8-13 所示,实例化 HauntedBus 时,如果 传入乘客,会按预期运作。但是不为 HauntedBus 指定乘客的话,奇怪 的事就发生了,这是因为 self.passengers 变成了 passengers 参数 默认值的别名。出现这个问题的根源是,默认值在定义函数时计算(通 常在加载模块时),因此默认值变成了函数对象的属性。因此,如果默 认值是可变对象,而且修改了它的值,那么后续的函数调用都会受到影 响。

运行示例 8-13 中的代码之后,可以审查 HauntedBus.__init__ 对 象,看看它的 __defaults__ 属性中的那些幽灵学生:

>>> dir(HauntedBus.__init__) # doctest: +ELLIPSIS
[‘__annotations__‘, ‘__call__‘, ..., ‘__defaults__‘, ...]
>>> HauntedBus.__init__.__defaults__
([‘Carrie‘, ‘Dave‘],)

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

>>> HauntedBus.__init__.__defaults__[0] is bus2.passengers
True

可变默认值导致的这个问题说明了为什么通常使用 None 作为接收可变 值的参数的默认值。在示例 8-8 中,__init__ 方法检查 passengers 参数的值是不是 None,如果是就把一个新的空列表赋值给 self.passengers。下一节会说明,如果 passengers 不是 None,正 确的实现会把 passengers 的副本赋值给 self.passengers。下面详 解。

原文地址:https://www.cnblogs.com/xiangxiaolin/p/11719549.html

时间: 2024-10-07 12:17:41

不要使用可变类型作为参数的默认值的相关文章

?Swift语言中为外部参数设置默认值,可变参数,常量参数,变量参数,输入输出参数

引用自这里:Swift语言中为外部参数设置默认值可变参数常量参数变量参数输入输出参数 目录[-] 7.4.4  为外部参数设置默认值 7.4.5  可变参数 7.4.6  常量参数和变量参数 7.4.7  输入-输出参数 7.4.4  为外部参数设置默认值 开发者也可以对外部参数设置默认值.这时,调用的时候,也可以省略参数传递本文选自Swift1.2语言快速入门v2.0. [示例7-11]以下的代码就为外部参数toString.withJoiner设置了默认的参数"Swift"和&qu

?Swift语言中为外部参数设置默认值可变参数常量参数变量参数输入输出参数

Swift语言中为外部参数设置默认值可变参数常量参数变量参数输入输出参数 7.4.4  为外部参数设置默认值 开发者也可以对外部参数设置默认值.这时,调用的时候,也可以省略参数传递本文选自Swift1.2语言快速入门v2.0. [示例7-11]以下的代码就为外部参数toString.withJoiner设置了默认的参数"Swift"和"---".代码如下: import Foundation func join(string s1: String, toString

【C#】妈妈再也不用担心自定义控件如何给特殊类型的属性添加默认值了,附自定义GroupBox一枚

标题有点那啥,但确实能表达我掌握此法后的心情. 写自定义控件时往往会有一个需求,就是给属性指定一个默认值(就是可以在VS中右键该属性→重置),如果该属性的类型是内置值类型还好,直接使用DefaultValue特性就好,例如: [DefaultValue(false)] public bool CanSelect { get; set; } 对于能够根据字符串常量转换得到的类型也还好,可以这样: [DefaultValue(typeof(Font), "宋体, 9pt")] public

自定义控件如何给特殊类型的属性添加默认值 z(转)

自定义控件如何给特殊类型的属性添加默认值 z 定义控件如何给特殊类型的属性添加默认值了,附自定义GroupBox一枚 标题有点那啥,但确实能表达我掌握此法后的心情. 写自定义控件时往往会有一个需求,就是给属性指定一个默认值(就是可以在VS中右键该属性→重置),如果该属性的类型是内置值类型还好,直接使用DefaultValue特性就好,例如: [DefaultValue(false)] public bool CanSelect { get; set; } 对于能够根据字符串常量转换得到的类型也还

自定义控件如何给特殊类型的属性添加默认值 z

定义控件如何给特殊类型的属性添加默认值了,附自定义GroupBox一枚 标题有点那啥,但确实能表达我掌握此法后的心情. 写自定义控件时往往会有一个需求,就是给属性指定一个默认值(就是可以在VS中右键该属性→重置),如果该属性的类型是内置值类型还好,直接使用DefaultValue特性就好,例如: [DefaultValue(false)] public bool CanSelect { get; set; } 对于能够根据字符串常量转换得到的类型也还好,可以这样: [DefaultValue(t

ES6 函数参数的默认值

基本用法 在ES6之前,不能直接为函数的参数指定默认值,只能采取变通的方法. function log(x,y){ y = y||'world'; console.log(x,y); } log('kkk');//kkk world 这种写法的缺点在于: 如果参数y赋值了,但是对应的布尔值为false,则该赋值不起作用.如果在调用函数的时候,传入的y参数是一个空字符串,那么y就会被修改为默认值. 避免这个问题,需要先判断一下:1.通过判断值是否等于undefined,2.判断arguments.

gluster 3.4.5参数及默认值

1 参数及默认值 $gluster-option                                 OPTION: DEFAULT_VALUE            diagnostics.brick-log-level: INFO                network.tcp-window-size: (null)         performance.least-prio-threads: 1                performance.open-behin

(转)js函数参数设置默认值

原文:http://www.cnblogs.com/RightDear/archive/2013/06/26/3156652.html js函数参数设置默认值 php有个很方便的用法是在定义函数时可以直接给参数设默认值,如: function simue ($a=1,$b=2){   return $a+$b; } echo simue(); //输出3 echo simue(10); //输出12 echo simue(10,20); //输出30 但js却不能这么定义,如果写function

js 的函数参数的默认值问题

js函数参数设置默认值 php有个很方便的用法是在定义函数时可以直接给参数设默认值,如: function simue ($a=1,$b=2){ return $a+$b; } echo simue(); //输出3 echo simue(10); //输出12 echo simue(10,20); //输出30 但js却不能这么定义,如果写function simue(a=1,b=2){}会提示缺少对象. js函数中有个储存参数的数组arguments ,所有函数获得的参数会被编译器挨个保存到