流畅的 Python 阅读记录五:深浅拷贝
主要涉及到 Python 中类的成员变量传参问题, 非常重要. 这里的代码可以在 python可视化网站 中进行查看, 非常有用!!
1. 要知道 Python 中 列表 是可变的, 元组 是不可变的, 究竟是什么意思.
2. 了解列表和元组作为函数参数, 改变它们会有什么不同效果?
3. 把空列表作为默认参数, 可能会有非常大的问题
4. 当列表作为参数传给类的成员变量, 修改成员变量时可能会对原有列表产生误操作
列表可变、元组不可变的深层分析
l1 = [3, [66, 55, 44], (7, 8, 9)]
l2 = list(l1)
l1.append(100)
l1[1].remove(55)
print('l1:', l1)
print('l2:', l2)
l1: [3, [66, 44], (7, 8, 9), 100]
l2: [3, [66, 44], (7, 8, 9)]
第二句的执行过程:
l1 = [3, [66, 55, 44], (7, 8, 9)]
l2 = list(l1)
l2[1] += [33, 22]
l2[2] += (10, 11)
print('l1:', l1)
print('l2:', l2)
l1: [3, [66, 55, 44, 33, 22], (7, 8, 9)]
l2: [3, [66, 55, 44, 33, 22], (7, 8, 9, 10, 11)]
不同元素作为函数参数, 改变它们会有什么不同效果?
def f(a, b):
a += b
x1, y1 = 1, 2
f(x1, y1)
x2, y2 = [1, 2], [3, 4]
f(x2, y2)
x3, y3 = (1, 2), (3, 5)
f(x3, y3)
print(x1, x2, x3)
1 [1, 2, 3, 4] (1, 2)
列表作为参数,不传参可能会有非常大的问题
class HauntedBus:
def __init__(self, passengers=['Default'], int_example=3):
self.passengers = passengers
self.int_example = int_example
def pick(self, name):
self.passengers.append(name)
self.int_example += 1
bus1 = HauntedBus(['Alice', 'Bill'], 5)
bus2 = HauntedBus()
bus3 = HauntedBus()
bus1.pick('Bus1')
bus2.pick('Bus2')
bus3.pick('Bus3')
print(bus1.passengers)
print(bus2.passengers)
print(bus3.passengers)
['Alice', 'Bill', 'Bus1']
['Default', 'Bus2', 'Bus3']
['Default', 'Bus2', 'Bus3']
执行 bus2
的初始化时:
执行 bus3
的初始化后:
解决方式:改成 self.passengers = list(passengers)
就行了。当然最好的方式是做判断。
def __init__(self, passengers=None, int_example=3):
self.passengers = passengers if passengers else ['Default']
self.int_example = int_example
列表作为参数,传参也可能有问题
class TwilightBus:
def __init__(self, passengers):
self.passengers = passengers
def drop(self, name):
self.passengers.remove(name)
basketball_team = ['Sue', 'Tina', 'Maya', 'Diana', 'Pat']
bus = TwilightBus(basketball_team)
bus.drop('Tina')
print(basketball_team)
['Sue', 'Maya', 'Diana', 'Pat']
这个原因很显然了,列表作为参数,用了浅拷贝。所以之后对于列表的参数一定要小心,要知道自己需不需要修改这个传入的参数。