# -*- coding: utf-8 -*-
# @Time : 2019/11/27 20:08
# @Author : John
# @Email : 2398344557@qq.com
# @File : 賦值+拷貝.py
# @Software: PyCharm
賦值/函數(shù)參數(shù)傳遞
傳遞的永遠都是對象引用(內(nèi)存地址)制肮,而不是對象的內(nèi)容
因為指向的都是同一塊內(nèi)存
所以冒窍,內(nèi)外層共享,你變我也變
對象分為兩種:可變對象(mutable)和不可變對象(immutable)
類型不同豺鼻,決定了可以對它進行的操作不同综液。
對象的拷貝是指在內(nèi)存中創(chuàng)建新的對象,產(chǎn)生新的內(nèi)存地址儒飒。
當頂層對象和它的子元素對象全為immutable不可變對象時谬莹,不存在被拷貝,因為沒有產(chǎn)生新對象桩了。
可變對象(mutable)
例如:list附帽、dict、
不可變對象(immutable)
例如:number圣猎、string士葫、tuple、frozenset
賦值/函數(shù)參數(shù)傳遞:傳遞的永遠是對象引用(即內(nèi)存地址)送悔,而不是對象內(nèi)容慢显。
淺拷貝(Shallow Copy):拷貝頂層對象,但不會拷貝內(nèi)部子元素對象欠啤。
深拷貝(Deep Copy):遞歸拷貝頂層對象荚藻,以及它內(nèi)部的子元素對象。
a = 1
b = a
print(id(a)) # a指向了1所應(yīng)有的內(nèi)存
print(id(b)) # b也指向了1所應(yīng)有的內(nèi)存
# a == b
# id(a) == id(b)
# 1808255104
# 1808255104
b += 1
print(a) # a指向了1所應(yīng)有的內(nèi)存
print(b) # b另尋新歡洁段,指向了2所對應(yīng)的內(nèi)存
print(id(a))
print(id(b))
# a != b
# id(a) != id(b)
# 1
# 2
# 1808255104
# 1808255120
a += 1
print(a) # a指向了2所應(yīng)有的內(nèi)存
print(b) # b指向了2所對應(yīng)的內(nèi)存
print(id(a))
print(id(b))
# a == b
# id(a) == id(b)
# 2
# 2
# 1808255120
# 1808255120
# 結(jié)論:
# 要是b改變了应狱,那么a不受影響
# 要是a改變了,b會跟著改變
# Python會緩存使用頻率較多的整數(shù)-5到256祠丝、ISO/IEC 8859-1單字符疾呻、包括大小寫英文字母的字符串,以對其復用写半,不會創(chuàng)建新對象
a = 1000000000
b = 1000000000
print(id(a))
print(id(b))
a = -10
b = -10
print(id(a))
print(id(b))
a = 'x*y'
b = 'x*y'
print(id(a))
print(id(b))
a = 'Hello World'
b = 'Hello World'
print(id(a))
print(id(b))
------------------------------------------------------------------------
copy模塊
- 對象拷貝是指內(nèi)存中創(chuàng)建新的對象岸蜗,產(chǎn)生新的內(nèi)存地址
- 淺拷貝只拷貝最外層對象,深拷貝還會遞歸拷貝內(nèi)層對象
- 無論是淺拷貝還是深拷貝叠蝇,只拷貝mutable可變對象成為一個新對象璃岳;而immutable不可變對象還是原來的那個
- 當頂層對象和它的子元素對象全都是immutable不可變對象時,因為沒有產(chǎn)生新對象悔捶,所以不存在被拷貝
淺拷貝(Shallow Copy):拷貝頂層對象铃慷,但不會拷貝內(nèi)部的子元素對象
- 頂層是mutable,子元素全是immutable
# 當頂層對象時mutable可變對象蜕该,但是它的子元素對象全都是immutable不可變對象時犁柜,例如[1, 'world', 2]
a = [1, 'world', 2]
from copy import copy
b = copy(a)
# 最外層
print(a)
print(b)
print(id(a))
print(id(b))
# 第一層
print([id(item) for item in a])
print([id(item) for item in b])
a[0] = 3 # 整數(shù)為不可改變對象
a[1] = 'back' # 字符串為可改變對象
print(a)
print(b)
print(id(a))
print([id(item) for item in a])
print(id(b))
print([id(item) for item in b])
# [3, 'back', 2]
# [1, 'world', 2]
# 205803315784
# [140715228312464, 205808370440, 140715228312432]
# 205803315848
# [140715228312400, 205803779440, 140715228312432]
# 結(jié)論:
# 淺拷貝:
# 最外層內(nèi)存地址改變
# 第一層內(nèi),改變immutable對象時堂淡,元素內(nèi)存地址改變馋缅;改變mutable對象時坛怪,元素內(nèi)存地址不變
- 頂層是mutable,子元素部分是immutable
# 當頂層對象時mutable可變對象股囊,但子元素也存在mutable可變對象時,如[1, 2, ['hello', 'word']]
a = [1, 2, ['hello', 'world']]
from copy import copy
b = copy(a)
# 最外層
print(id(a))
print(id(b))
# 第一層
print([id(item) for item in a])
print([id(item) for item in b])
# 第二層
print([id(item) for item in a[2]])
print([id(item) for item in b[2]])
# 最外層
# 147762995848
# 147890515400
# 第一層
# [140714968986448, 140714968986480, 147762995784]
# [140714968986448, 140714968986480, 147762995784]
# 第二層
# [147763459440, 147763459496]
# [147763459440, 147763459496]
a[2][1] = 'china'
print(a)
print(b)
# 第二層()
print([id(item) for item in a[2]])
print([id(item) for item in b[2]])
# [1, 2, ['hello', 'china']]
# [1, 2, ['hello', 'china']]
# [879935386992, 879935387216]
# [879935386992, 879935387216]
# -----------
b[2][1] = 'china'
print(a)
print(b)
# 第二層()
print([id(item) for item in a[2]])
print([id(item) for item in b[2]])
# [1, 2, ['hello', 'china']]
# [1, 2, ['hello', 'china']]
# [853162423664, 853162423888]
# [853162423664, 853162423888]
- 頂層是immutable更啄,子元素全是immutable
# 當頂層對象是immutable不可變對象稚疹,同時子元素對象也全是immutable不可變對象時,例如(1, 2, 3)
a = (1, 2, 3)
from copy import copy
b = copy(a)
# 最外層
print(id(a))
print(id(b))
# 第一層
print([id(item) for item in a])
print([id(item) for item in b])
# 926788983616
# 926788983616
# [140715035439952, 140715035439984, 140715035440016]
# [140715035439952, 140715035439984, 140715035440016]
# 結(jié)論:變量a與變量b指向的是同一個元組對象祭务,沒有拷貝
- 頂層是immutable内狗,子元素部分mutable
# 當頂層對象是immutable不可變對象時,但子元素存在mutable可變對象時义锥,如(1, 2, ['hello','world'])
a = (1, 2, ['hello', 'world'])
from copy import copy
b = copy(a)
# 最外層
print(id(a))
print(id(b))
# 第一層
print([id(item) for item in a])
print([id(item) for item in b])
# 第二層
print([id(item) for item in a[2]])
print([id(item) for item in b[2]])
# 956919749512
# 956919749512
# [140715035439952, 140715035439984, 956889129544]
# [140715035439952, 140715035439984, 956889129544]
# [956916987248, 956916987304]
# [956916987248, 956916987304]
# 修改第二層
a[2][1] = 'china'
print(a)
print(b)
# b[2][1] = 'china'
# print(a)
# print(b)
# # (1, 2, ['hello', 'china'])
# # (1, 2, ['hello', 'china'])
# 結(jié)論:變量a和變量b指向同樣的元租對象柳沙,并且a[2]與b[2]指向同一個列表,所以修改a[2][1]會影響b[2][1]
深拷貝(Deep Copy):遞歸拷貝頂層對象拌倍,以及它內(nèi)部的子元素對象
- 頂層是mutable赂鲤,子元素全是immutable
# 當頂層對象是mutable可變對象,但是它的子元素對象全都是immutable不可變對象時柱恤,如[1, 'world', 2]
a = [1, 'world', 2]
from copy import deepcopy
b = deepcopy(a)
print(a)
print(b)
print(id(a))
print(id(b))
# 第一層
print([id(item) for item in a])
print([id(item) for item in b])
# 第二層
print([id(a[1])])
print([id(b[1])])
# [1, 'world', 2]
# [1, 'world', 2]
# 249343140424
# 249343140488
# [140715035439952, 249343604080, 140715035439984]
# [140715035439952, 249343604080, 140715035439984]
# 249343604080
# 249343604080
# a[0] = 3
# a[1] = 'xuebi'
# print(a)
# print(b)
# print([id(item) for item in a])
# print([id(item) for item in b])
# b[0] = 3
# b[1] = 'xuebi'
# print(a)
# print(b)
# print([id(item) for item in a])
# print([id(item) for item in b])
# 結(jié)論:變量a與變量b指向不同的列表對象数初,修改a[0]只是將列表a的第一個元素重新指向新對象,不會影響b[0]
- 頂層是immutable梗顺,子元素部分mutable
# 當頂層對象是immutable不可變對象時泡孩,但子元素存在mutable可變對象時,如(1, 2, ['hello','world'])
a = (1, 2, ['hello', 'world'])
import copy
b = copy.deepcopy(a)
# 最外層
print(id(a))
print(id(b))
# 第一層
print([id(item) for item in a])
print([id(item) for item in b])
# 第二層
print([id(item) for item in a[2]])
print([id(item) for item in b[2]])
# 最外層
# 6333064
# 74784040
# 第一層
# [1685506176, 1685506192, 1656272]
# [1685506176, 1685506192, 74867736]
# 第二層
# [2289152, 2289184]
# [2289152, 2289184]
a[2][1] = 'china'
print(a)
print(b)
print([id(item) for item in a[2]])
print([id(item) for item in b[2]])
# (1, 2, ['hello', 'china'])
# (1, 2, ['hello', 'world'])
# [2289152, 2289280]
# [2289152, 2289184]
# 結(jié)論:變量a與變量b指向的是不同的元組對象寺谤,同時a[2]與b[2]指向不同的列表對象仑鸥,所以修改a[2][1]不會影響b[2][1]
【例子】
class dog:
def __init__(self, age):
self.age = age
self.foods = ['gutou', 'gouliang', 'jichibang']
def __repr__(self):
return f'dog is {self.age}, dog like eat {self.foods}.'
dog1 = dog(10)
print(dog1)
# dog is 10, dog like eat ['gutou', 'gouliang', 'jichibang'].
dog2 = copy.copy(dog1)
dog1.age = 50
dog1.foods[0] = 'maoliang'
print(dog1)
print(dog2)
# dog is 50, dog like eat ['maoliang', 'gouliang', 'jichibang'].
# dog is 10, dog like eat ['maoliang', 'gouliang', 'jichibang'].
# 分析:
# 年齡在第一層,不變变屁;foods列表在第二層眼俊,會變
【例子】
class home:
def __init__(self, addr):
self.addr = addr
def __repr__(self):
return self.addr
class dog:
def __init__(self, age, addr, name):
self.name = name
self.age = age
self.home = home(addr)
def __repr__(self):
return f'dog is {self.age}, my home is {self.home}, my name is {self.name}'
dog1 = dog(20, '美國', 'ruhua')
print(dog1)
# dog is 20, my home is 美國, my name is ruhua
dog2 = copy.copy(dog1)
dog1.age = 30
dog1.name = 'panghu'
dog1.home.addr = 'afuhan'
print(dog1)
print(dog2)
# dog is 30, my home is afuhan, my name is panghu
# dog is 20, my home is afuhan, my name is ruhua
# 分析:
# age和name在第一層,不變敞贡;home在第二層泵琳,會變
其它拷貝方法
- 列表的復制
a = [1, 2, 3]
b = a
# 變化前:a == b
print(b)
print(id(a))
print(id(b))
a[0] = 'xuebi'
# 變化后:a == b
print(a)
print(b)
print(id(a))
print(id(b))
# [1, 2, 3]
# 4933072
# 4933072
# ['xuebi', 2, 3]
# ['xuebi', 2, 3]
# 4933072
# 4933072
# 但是,列表的復制也會有淺拷貝的效果誊役,如下:
a = [1, 2, ['hello','world']]
# 1. 列表的copy()函數(shù)
b = a.copy()
# 2. list()轉(zhuǎn)換函數(shù)
c = list(a)
# 3. 列表分片[:]
d = a[:]
print(id(a), id(b), id(c), id(d))
# 4672088 74736824 13781432 13648800
a[0] = 100
a[2][1] = 'wangy'
print(a)
print(b)
print(c)
print(d)
print(id(a), id(b), id(c), id(d))
# [100, 2, ['hello', 'wangy']]
# [1, 2, ['hello', 'wangy']]
# [1, 2, ['hello', 'wangy']]
# [1, 2, ['hello', 'wangy']]
# 4672088 74736824 13781432 13648800
# 結(jié)論:b/c/d都是a的復制获列,它們都指向了不同的列表對象,但是沒有拷貝子元素蛔垢,a[2]和b[2]/c[2]/d[2]指向同一個列表击孩,相當于淺拷貝的效果
- 元組的復制
a = (1, 2, ['hello','world'])
b = a[:]
print(id(a), id(b))
print(a)
print(b)
# 35496504 35496504
# (1, 2, ['hello', 'world'])
# (1, 2, ['hello', 'world'])
a[2][1] = 'wangy'
print(a)
print(b)
print(id(a), id(b))
# (1, 2, ['hello', 'world'])
# (1, 2, ['hello', 'world'])
# (1, 2, ['hello', 'wangy'])
# (1, 2, ['hello', 'wangy'])
# 35496504 35496504
# 結(jié)論:使用分片[:]操作,a和b其實是指向同一個元組鹏漆,而且沒有拷貝子元素巩梢,a[2]和b[2]也指向同一個列表创泄,相當于淺拷貝的效果
- 字典的復制
# 字典的復制
# 同列表類似,可以使用字典的copy()函數(shù)或者轉(zhuǎn)換函數(shù)dict()
a = {'name': 'wangy', 'age': 18, 'jobs': ['devops', 'dba']}
b = a.copy()
c = dict(a)
print(id(a), id(b), id(c))
# 14499392 14012304 5470848
a['age'] = 20
a['jobs'].append('python')
print(a)
print(b)
print(c)
print(id(a), id(b), id(c))
# {'name': 'wangy', 'age': 20, 'jobs': ['devops', 'dba', 'python']}
# {'name': 'wangy', 'age': 18, 'jobs': ['devops', 'dba', 'python']}
# {'name': 'wangy', 'age': 18, 'jobs': ['devops', 'dba', 'python']}
# 14499392 14012304 5470848
# 結(jié)論:變量a與變量b/c指向不同的字典括蝠,但是沒有拷貝子元素鞠抑,a['jobs']和b['jobs']/c['jobs']指定同一個列表,相當于淺拷貝的效果
- 集合的復制
# 同列表類似忌警,可以使用集合的copy()函數(shù)或者轉(zhuǎn)換函數(shù)set()
a = {1, 2, 3}
b = a.copy()
c = set(a)
print(id(a), id(b), id(c))
# 2731824 35400440 35400560
a.add('wangy')
print(a)
print(b)
print(c)
print(id(a), id(b), id(c))
# {1, 2, 3, 'wangy'}
# {1, 2, 3}
# {1, 2, 3}
# 2731824 35400440 35400560
# 結(jié)論:變量a與變量b/c指向不同的集合搁拙,而集合的元素必須是hashable,所以修改集合a不會影響到b/c