话不多说,上代码:
def fun(x, A=[], B=''):
C = []
A.append(x)
B = B + x
C.append(x)
print(f"A:{A} B:{B} C:{C}")
fun('1')
fun('2')
fun('3')
我们在这段代码中:
定义了一个位置参数 x,一个一个默认参数 A,A 的默认值为空列表,另一个默认参数 B,B 的默认值为一个空字符串,在函数体中定义了一个变量 C,并也给 C 传递了一个空列表。
大家猜猜函数执行会输出怎样一个结果?
# 为了排版工整略微修改了一下输出样式
A:['1'] B:1 C:['1']
A:['1', '2'] B:2 C:['2']
A:['1', '2', '3'] B:3 C:['3']
大家猜到了这个结果了吗?猜到的朋友都是大佬,下面的内容就可以略过了。没有猜到的朋友也不要慌,毕竟这玩意儿有点坑。。。
在解释这个结果之前,大家需要复习一下 Python 中可变对象和不可变对象这两个概念:
- 可变对象:对象指向的内存中的值会改变,当更改这个变量的时候,还是指向原来内存中的值,并且在原来的内存值进行原地修改,并没有开辟新的内存(list、dict、set);
- 不可变对象:对象所指向的内存中的值不能被改变,当改变这个变量的时候,原来指向的内存中的值不变,变量不再指向原来的值,而是开辟一块新的内存,变量指向新的内存(int、float、str、tuple、bool、None)。
概念复习完了就开始进入正题了:
在Python程序中,函数在被定义创建时,Python就会为默认参数分配一块儿空间。在这个程序中,为默认变量 A 分配了一个内存地址,其中的值为一个空列表,为 B 也分配了一块儿空间,值为空字符串:
地址:0x0001 值:[] ==> A
地址:0x0002 值:'' ==> B
Python 在调用函数时,会直接将在函数定义时得到的内存地址复制给默认参数!
因此会在调用函数时出现下面的内存变化(内存地址为了方便看才排列这样有序的,实际程序里不可能这样):
扫描二维码关注公众号,回复:
11537384 查看本文章
当第一次调用函数时:
# 调用开始时: A指向0x0001这个地址,B指向0x0002这个地址
C = [] # 对象C指向一个空列表
A.append(x) # 对象A指向的空列表(地址:0x0001)中添加了'1'
B = B + x # 开辟了一块儿新内存,其中值为'1',B不再指向''(地址:0x0002)而指向'1'
C.append(x) # 对象C指向的空列表中添加了'1'
print(f"A:{A} B:{B} C:{C}") # A:['1'] B:'1' C:['1']
函数执行完后内存指向:
地址:0x0001 值:['1'] ==> A
地址:0x0002 值:''
地址:0x0003 值:['1'] ==> C
地址:0x0004 值:'1' ==> B
当第二次调用函数时:
# 调用开始时: A指向0x0001这个地址,B指向0x0002这个地址
C = [] # 对象C指向一个空列表
A.append(x) # 对象A指向的空列表(地址:0x0001)中添加了'2'
B = B + x # 开辟了一块儿新内存,其中值为'2',B不再指向''(地址:0x0002)而指向'2'
C.append(x) # 对象C指向的空列表中添加了'2'
print(f"A:{A} B:{B} C:{C}") # A:['1', '2'] B:'2' C:['2']
函数执行完后内存指向:
地址:0x0001 值:['1', '2'] ==> A
地址:0x0002 值:''
地址:0x0003 值:['2'] ==> C
地址:0x0004 值:'2' ==> B
当第三次调用函数时:
# 调用开始时: A指向0x0001这个地址,B指向0x0002这个地址
C = [] # 对象C指向一个空列表
A.append(x) # 对象A指向的空列表(地址:0x0001)中添加了'3'
B = B + x # 开辟了一块儿新内存,其中值为'3',B不再指向''(地址:0x0002)而指向'3'
C.append(x) # 对象C指向的空列表中添加了'3'
print(f"A:{A} B:{B} C:{C}") # A:['1', '2', '3'] B:'3' C:['3']
函数执行完后内存指向:
地址:0x0001 值:['1', '2', '3'] ==> A
地址:0x0002 值:''
地址:0x0003 值:['3'] ==> C
地址:0x0004 值:'3' ==> B
经过俺的这番讲解,朋友们你们学废了吗?
为了避免以后在程序中出现莫名其妙的 Bug,大家要记住在 Python 程序中
默认参数的值应该为不可变对象!!!
默认参数的值应该为不可变对象!!!
默认参数的值应该为不可变对象!!!