对象的复制赋值

目录

  • 潜复制&深复制
  • 值传递&引用传递
  • 可变对象&不可变对象

赋值

对象的赋值实际上是对象的引用。
当创建一个对象,然后把它赋给另一个变量的时候,python并没有拷贝这个对象,而只是拷贝了这个对象的引用。

  1. 直接赋值
    默认浅拷贝传递对象的引用而已,原始列表改变,被赋值的b也会做相同的改变
alist = [1,2,3,['a','b']]
blist = alist
  1. 浅拷贝
    没有拷贝子对象,所以原始数据改变,子对象会改变
def add_data():
    alist = [1, 2, 3, ['a', 'b']]
    import copy
    clist = copy.copy(alist)         --没有拷贝子对象,公用一个可变list对象
    print(alist, clist)
    clist.append(5)             --非可变子对象,不改变clist
    print(alist, clist)
    print(alist[3])              -- 可变改变clist
    alist[3].append('qqq')
    print(alist, clist)

if __name__ == '__main__':
    add_data()

--输出结果
[1, 2, 3, ['a', 'b']] [1, 2, 3, ['a', 'b']]
[1, 2, 3, ['a', 'b']] [1, 2, 3, ['a', 'b'], 5]
['a', 'b']
[1, 2, 3, ['a', 'b', 'qqq']] [1, 2, 3, ['a', 'b', 'qqq'], 5]
  1. 深拷贝
    包含对象里面的自对象的拷贝,所以原始对象的改变不会造成深拷贝里任何子元素的改变
def add_data():
    alist = [1, 2, 3, ['a', 'b']]
    import copy
    clist = copy.deepcopy(alist)
    print(alist, clist)
    alist.append(5)
    print(alist, clist)
    print(alist[3])
    alist[3].append('qqq')
    print(alist, clist)
--alist始终没有改变

if __name__ == '__main__':
    add_data()

--输出结果
[1, 2, 3, ['a', 'b']] [1, 2, 3, ['a', 'b']]
[1, 2, 3, ['a', 'b'], 5] [1, 2, 3, ['a', 'b']]
['a', 'b']
[1, 2, 3, ['a', 'b', 'qqq'], 5] [1, 2, 3, ['a', 'b']]

可变对象

该对象所指向的内存中的值不能被改变。
当改变某个变量时候,由于其所指的值不能被改变,相当于把原来的值复制一份后再改变,这会开辟一个新的地址,变量再指向这个新的地址。

不可变对象

该对象所指向的内存中的值可以被改变。
变量(准确的说是引用)改变后,实际上是其所指的值直接发生改变,并没有发生复制行为,也没有开辟新的出地址,通俗点说就是原地改变。

  • 数字
def add_data():
    a = 2
    b = 2
    c = a + 0
    # c += 0
    print(id(a), id(b), id(2))
    print(c is b)
    print(a is b)
    print(a == b)

if __name__ == '__main__':
    add_data()

--输出结果
140721525199712 140721525199712 140721525199712
True
True
True
  • 字符串
def add_data():
    a = 'qly'
    b = 'qly'
    c = a + ''
    # c += 0
    print(id(a), id(b), id(2))
    print(c is b)
    print(a == b)

if __name__ == '__main__':
    add_data()

--输出结果
2038701311344 2038701311344 140721525199712
True
True


def add_data():
    a = 'qly'
    print(id(a))
    a += 'qq'
    print(id(a))


if __name__ == '__main__':
    add_data()

--输出结果
2711470425456
2711483786944
  • 解释
    不可变对象,变量对应内存的值不允许被改变。
    当变量要改变时,实际上是把原来的值复制一份,开辟一个新的内存地址,a再指向这个新的地址,那么此时 id() 输出的值不一样了。
    而原来a对应的值 因为不再有对象指向它,被垃圾回收了。
    int 和 float 同理。

  • 元组

def add_data():
    aac = (1, 2, 3)
    aab = (1, 2, 3)
    print(id((1, 2, 3)))
    print(id(aac))
    print(id(aab))
    aad = (1, 2, 3)
    aad += ()
    print(aad)
    print(id(aad))

if __name__ == '__main__':
    add_data()

--输出结果
2461327044256
2461327044256
2461327044256
(1, 2, 3)
2461327044256
def add_data():
    aab = (1, 2, 3)
    print(id(aab))
    aad = aab
    aad += (4, 5, 6)
    print(aad)
    print(id(aad))

if __name__ == '__main__':
    add_data()

--输出结果
2100321332896
(1, 2, 3, 4, 5, 6)
2100334933480

可变对象-list

def add_data():
    aab = [1, 2, 3]
    print(id(aab))
    aac = [1, 2, 3]
    print(id(aac))     --内容一样,但指向不同的内存地址

if __name__ == '__main__':
    add_data()

--输出结果
2073896330632
2073896281096
--赋值
def add_data():
    aab = [1, 2, 3]
    print(id(aab))   -- aac 实际上是对 对象的引用,
    aac = aab  --值传递,两个引用指向同一个对象
    print(id(aac))
    # 所以其中一个变化,会影响到另外一个
    aac.append(5)
    print(aab)
    print(id(aab),id(aac))


if __name__ == '__main__':
    add_data()

--输出结果
2498063397320
2498063397320

可变对象-set

def add_data():
    aab = {1, 2, 3}
    aac = aab
    print(id(aab))
    print(id(aac))
    aac.add(5)
    print(aab)
    print(id(aab),id(aac))


if __name__ == '__main__':
    add_data()

--输出结果
2871438648936
2871438648936
{1, 2, 3, 5}
2871438648936 2871438648936

和list同理

可变对象,直接原地改变该值,不开辟新内存,改变前后id不变

def add_data():
    aab = '666'
    aac = aab
    print(id(aab))
    print(id(aac))
    aac = '999'            -- aab 不随 aac 的改变而改变
    print(aab, aac)
    print(id(aab),id(aac))


if __name__ == '__main__':
    add_data()

--输出结果
2000643574784
2000643574784
666 999
2000643574784 2000643574896
def add_data():
    aalist = [1,2,3]
    blist = aalist[:]
    print(aalist is blist)


if __name__ == '__main__':
    add_data()

--输出结果
False

函数参数--值传递&引用传递

--可变类型传递的是引用,相当于对象的值
def change(aalist):
    aalist.append(7)

--不可变类型传递的是内容,相当于复制再传递
def not_change(astr):
    astr.lower()

if __name__ == '__main__':
    test_list = [1,2,3,4]
    test_str = 'HALO'
    change(test_list)
    not_change(test_str)
    print(test_list)
    print(test_str)

--输出结果
[1, 2, 3, 4, 7]
HALO
--如果不想改变原来列表的值,参数可以传入列表的拷贝

list和+

def add_data():
    aa = [1,2,3]
    bb = aa         
    print(id(aa), id(bb))       实际上bb已经指向新的对象,id已改变
    -- aa  和  bb 不是同一个对象的引用, bb变化,aa不变
    bb = bb + [4]          --赋值成功,bb就指向新的对象
    print(id(aa), id(bb))      --不等, bb的id变了
    print(aa)
    cc = aa
    cc += [4]             --相当于调用bb.extend([4]),原地改变并没有新的对象产生
    print(id(aa), id(cc))       --相等,指向同一个对象
    print(aa)

if __name__ == '__main__':
    add_data()
--输出结果
1532168349128 1532168349128
1532168349128 1532168348680
[1, 2, 3]
1532168349128 1532168349128
[1, 2, 3, 4]

浅拷贝

你可能感兴趣的:(对象的复制赋值)