默认参数
先看一个默认参数的坑:
class Player:
def __init__(self, name, items=[]):
self.name = name
self.items = items
print(id(self.items))
if __name__ == '__main__':
p1 = Player("Alice")
p2 = Player("Bob")
p3 = Player("dc", ["sword"])
p1.items.append("armor")
p2.items.append("sword")
print(p1.items)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
玩家 有name(姓名)和items(身上的道具). 通常情况下, 大部分玩家一开始是没有道具的 [], 只有付费玩家一开始有道具["sword"].
为了方便就在初始化函数__init__
里设置了默认参数 items=[]
.
后来, Alice和Bob才通过努力获取到了道具, p1.items.append("armor")
、p2.items.append("sword")
乍一看, 没啥问题. 实则掉入了 默认参数的陷阱. 打印结果进行验证:
4438029888
4438029888
4437884608
['armor', 'sword']
1
2
3
4
2
3
4
我们只给了Alice道具 armor , 但根据打印结果,可知 他有 armor和sword. Why?
《官方文档解释》:
当函数被定义的时候,只会把这个默认参数表达式求一次值.然后每一次调用的时候,默认参数都会使用这个值.
注:当你使用一个mutable的默认参数时,一定要理解你在干什么! (大部分情况下,这么使用都是不正确的
换句话说, p1和p2 初始化的时候 用的items是同一个list / Alice和Bob share(共享) 了一个 list.
而list在python里是mutable(可变)的. 所以就出现问题啦.
print(id(self.items))
可验证这个猜想, id()是一个 可以确认两个object是不是同一个 的方法.
那如何解决呢? 官方文档也给出了解决方案.
class Player:
def __init__(self, name, items=None):
self.name = name
if items is None:
self.items = []
else:
self.items = items
print(id(self.items))
if __name__ == '__main__':
p1 = Player("Alice")
p2 = Player("Bob")
p3 = Player("dc", ["sword"])
p1.items.append("armor")
p2.items.append("sword")
print(p1.items)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
看控制台打印结果, 默认参数的陷阱 解决啦!
4440774144
4440629056
4440773888
['armor']
1
2
3
4
2
3
4
-1- 判断None的时候, 一定要用is.
arg is None ; arg is not None 是可以的! arg == None 是不可以的!
-2- 自定义类型的对象可以成为字典的键吗? 大抵是有问题的.
-3-
1
2
3
4
2
3
4