Skip to content

流畅的 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']

这个原因很显然了,列表作为参数,用了浅拷贝。所以之后对于列表的参数一定要小心,要知道自己需不需要修改这个传入的参数。

Comments