Python类成员变量默认初始值的坑及解决
本文深入解析Python中类成员变量使用可变对象(如list)作为默认初始值时的常见陷阱。由于默认值仅在定义时初始化一次,导致所有实例共享同一内存地址,引发数据污染。文章通过代码示例展示问题现象,剖析根本原因,并提供使用None配合实例化初始化的标准解决方案,确保各实例数据独立。
类成员变量默认初始值的坑
问题发现
在循环中创建同名变量时,若使用缺省值初始化包含列表(list)的成员变量,该列表不会保持为空,而是会继承之前同名变量的值,导致数据串扰。
示例代码
# Define class
class Variant():
# use
def __init__(self, price = 500, description = 'default description', values = ['', '', '']):
self.price = price
self.description = description
self.values = values
def __str__(self):
return 'price: {}, description: {}, values: {}'.format(self.price, self.description, self.values)
variant_list = []
# Create instance with same name iteratively
for i in range(3):
current_variant = Variant()
if i == 1:
current_variant.values[2] = 'hello'
current_variant.price = i
current_variant.description = 'description of variant: {}'.format(i)
variant_list.append(current_variant)
# Test results
for variant in variant_list:
print(str(variant))结果
所有实例的values列表值相同
原因
在Python中,可选参数默认值的计算仅在函数定义时执行一次。这意味着,若使用缺省值初始化列表成员,所有实例中的该列表实际上指向的是同一个内存地址。如果仅修改其中一个元素的值(而非重新赋值一个新的列表以开辟新内存),那么所有实例的该列表成员都会被同步修改。
解决方法
直接在构造方法中将变量置为空(例如self.values = ['', '', '']),随后对各个实例单独修改值。
Python默认值参数
简单粗暴上代码
def fun(a, b=[]):
b += [a]
print(b)
fun(1)
fun(2,[])
fun(3)是不是看上去很简单,其实暗藏玄机,请大家看一下输出结果,是不是有点让你疑惑^^~
[1] [2] [1, 3]
此时你是否也和我有一样的疑惑,为什么 fun(3) 的输出结果是 [1, 3]?
哈哈,不卖关子了,这里是因为,因为函数被定义好后,只会生成一次,所以在函数生成的时候定义的变量 b 的默认值也只会被初始化一次。
因此,当执行fun(1)函数时,没有给 b 传参,所以使用的是 b 的默认值,此时 b 的默认值为[1]。
执行fun(2,[])时,给 b 传了一个[]值(恰好和默认值相同,其实是不同的数据),因此便使用的是传入数据,执行结果便是[2]。
然后在执行fun(3),此刻又没有给 b 传参,所以依旧使用的是 b 的默认值, 而 b 的默认值只会随着函数的生成被生成一次 ( fun(1) 生成过了 ),所以现在的默认值是fun(1)的执行结果[1],因此当fun(3)再次调用时,输出结果便会是[1, 3]。
如果不行出现当前这种情况,而是在函数每次被调用的时候都初始化一次变量
可以用下面这种写法
def function(a, b=None):
b = b if b else [] # 明确每次重新定义b
b += [a]
print(b)
function(1)
function(2, [])
function(3)输出结果:
[1] [2] [3]
以上为个人经验,希望能给大家一个参考,也希望大家多多支持本站。
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













