手机网站定制咨询,网站建设公司,做投资的网站,自己电脑做局域网网站服务器Python编程中#xff0c;我们有时会给函数或方法提供默认参数。然而#xff0c;这种做法在某些情况下可能会导致意想不到的行为#xff0c;尤其是当默认参数是可变对象#xff08;例如列表、字典或类实例对象#xff09;时。本文将通过几个具体的例子来解释这个问题#…Python编程中我们有时会给函数或方法提供默认参数。然而这种做法在某些情况下可能会导致意想不到的行为尤其是当默认参数是可变对象例如列表、字典或类实例对象时。本文将通过几个具体的例子来解释这个问题并提供解决方案。
问题示例
示例一HauntedBus类
首先考虑以下HauntedBus类
class HauntedBus:A bus model haunted by ghost passengersdef __init__(self, passengers[]):self.passengers passengersdef pick(self, name):self.passengers.append(name)def drop(self, name):self.passengers.remove(name)
在这个类中passengers参数有一个默认值[]。现在我们创建两个HauntedBus实例并向第一个实例添加乘客
bus1 HauntedBus()
bus1.pick(小明)
bus1.pick(小红)
print(bus1.passengers) # 输出: [小明, 小红]bus2 HauntedBus()
print(bus2.passengers) # 输出: [小明, 小红]
你可能会预期bus2的乘客列表应该是空的但实际输出表明它包含了bus1的乘客。这是为什么呢
示例二使用字典作为默认参数
def add_entry(key, value, dictionary{}):dictionary[key] valuereturn dictionaryd1 add_entry(name, Alice)
print(d1) # 输出: {name: Alice}d2 add_entry(age, 30)
print(d2) # 输出: {name: Alice, age: 30}
在这个例子中dictionary参数的默认值是一个空字典。第一次调用add_entry函数时向字典中添加了键值对name: Alice。第二次调用时字典中已经有了之前添加的键值对所以又添加了键值对age: 30。发现两次调用共享了同一个字典。
示例三使用自定义类对象作为默认参数
class DefaultObject:def __init__(self):self.data []print(DefaultObject Init)def add_to_default(objDefaultObject()):obj.data.append(1)return obj.dataresult1 add_to_default()
print(result1) # 输出: [1]result2 add_to_default()
print(result2) # 输出: [1, 1]
在这个例子中obj参数的默认值是一个DefaultObject实例。第一次调用add_to_default函数时向data列表中添加了数字1。第二次调用时data列表中已经有了一个1所以又添加了一个1。发现两次调用共享了同一个DefaultObject实例。
原因解析
在Python中默认参数是在函数定义的时候只初始化一次的而不是每次调用函数时重新初始化。如果默认参数是一个可变类型/对象那么后续对这个函数的调用将共享同一个默认参数对象。
解决方案
为了解决这个问题我们可以使用None作为默认参数值并在函数内部进行检查和初始化。这样每次创建新实例时都会创建一个新的可变对象从而避免不同实例或调用之间共享同一个默认参数对象。
修复后的HauntedBus类
class HauntedBus:A bus model haunted by ghost passengersdef __init__(self, passengersNone):if passengers is None:passengers []self.passengers passengersdef pick(self, name):self.passengers.append(name)def drop(self, name):self.passengers.remove(name)
现在我们再次创建两个HauntedBus实例并测试
bus1 HauntedBus()
bus1.pick(小明)
bus1.pick(小红)
print(bus1.passengers) # 输出: [小明, 小红]bus2 HauntedBus()
print(bus2.passengers) # 输出: []
这样每个实例都有自己独立的乘客列表不会相互影响。
修复后的add_entry函数
def add_entry(key, value, dictionaryNone):if dictionary is None:dictionary {}dictionary[key] valuereturn dictionaryd1 add_entry(name, Alice)
print(d1) # 输出: {name: Alice}d2 add_entry(age, 30)
print(d2) # 输出: {age: 30}
通过将默认参数设置为None并在函数内部进行初始化每次调用add_entry函数时都会创建一个新的字典从而避免不同调用之间共享同一个字典。
修复后的add_to_default函数
class DefaultObject:def __init__(self):self.data []print(DefaultObject Init)def add_to_default(objNone):if obj is None:obj DefaultObject()obj.data.append(1)return obj.dataresult1 add_to_default()
print(result1) # 输出: [1]result2 add_to_default()
print(result2) # 输出: [1]
通过将默认参数设置为None并在函数内部进行初始化每次调用add_to_default函数时都会创建一个新的DefaultObject实例从而避免不同调用之间共享同一个实例。
结论
在Python中使用默认参数时尤其是可变对象必须小心处理。通过使用None作为默认值并在函数内部进行初始化可以避免默认参数带来的潜在陷阱。希望这些例子能帮助你理解并避免类似的问题。 作者Black_Boy 链接https://juejin.cn/post/7376889083211300905