引用和拷貝

python中沒有賦值,只有引用。
(1)沒有限制條件的分片表達(dá)式(L[:])能夠復(fù)制序列,但此法只能淺層復(fù)制(淺復(fù)制出來的對(duì)象內(nèi)存地址和原來不一樣)。
(2)字典 copy 方法,D.copy() 能夠復(fù)制字典,但此法只能淺層復(fù)制
(3)有些內(nèi)置函數(shù),例如 list,能夠生成拷貝 list(L)
(4)copy 標(biāo)準(zhǔn)庫模塊能夠生成完整拷貝:deepcopy 本質(zhì)上是遞歸 copy(之前遇到過keystone.seesion來傳證書,然后發(fā)現(xiàn)參數(shù)里有session,同時(shí)還有其他參數(shù)里也包含了session,這樣不能deepcopy)
對(duì)象分為可變與不可變的,
可變:list set dict
可變對(duì)象更改的時(shí)候,內(nèi)存地址不變,只是區(qū)域長(zhǎng)度會(huì)變長(zhǎng)或變短;但不可變對(duì)象如string更改的時(shí)候,內(nèi)存地址會(huì)發(fā)生改變,及id(d)會(huì)變化即身份標(biāo)示
對(duì)象的三要素:id(身份標(biāo)示),type(數(shù)據(jù)類型)、value(值)
is比較的是兩個(gè)對(duì)象的id值是否相等,也就是比較兩個(gè)對(duì)象是否為同一個(gè)實(shí)例對(duì)象,是否指向同一個(gè)內(nèi)存地址。
==比較的是兩個(gè)對(duì)象的內(nèi)容是否相等,默認(rèn)會(huì)調(diào)用對(duì)象的eq()方法。

>>> b = 10**3
>>> a == b
True
>>> a is b
False
>>>
數(shù)字類型不一樣,id也不一樣
>>> c = 'pythontab.com'
>>> d = 'pythontab.com'
>>> c is d
False
>>> c == d
True
>>> c = 'pythontabcom'
>>> d = 'pythontabcom'
>>> c is c
True
>>> c == d
True
字符串類型不一樣,導(dǎo)致id不一樣

4.為什么修改全局的dict變量不用global關(guān)鍵字
為什么修改字典d的值不用global關(guān)鍵字先聲明呢?

s = 'foo'
d = {'a':1}
def f():
    s = 'bar'
    d['b'] = 2
f()
print s  # foo
print d  # {'a': 1, 'b': 2}

這是因?yàn)?,?】在s = 'bar'這句中,它是“有歧義的“,因?yàn)樗瓤梢允潜硎疽萌肿兞縮,也可以是創(chuàng)建一個(gè)新的局部變量,所以在python中,默認(rèn)它的行為是創(chuàng)建局部變量,除非顯式聲明global,global定義的本地變量會(huì)變成其對(duì)應(yīng)全局變量的一個(gè)別名,即是同一個(gè)變量。【2】在d['b']=2這句中,它是“明確的”,因?yàn)槿绻裠當(dāng)作是局部變量的話,它會(huì)報(bào)KeyError,所以它只能是引用全局的d,故不需要多此一舉顯式聲明global。

上面這兩句賦值語句其實(shí)是不同的行為,一個(gè)是rebinding(不可變對(duì)象), 一個(gè)是mutation(可變對(duì)象).
但是如果是下面這樣:

d = {'a':1}
def f():
    d = {}
    d['b'] = 2
f()
print d  # {'a': 1}

在d = {}這句,它是”有歧義的“了,所以它是創(chuàng)建了局部變量d,而不是引用全局變量d,所以d['b']=2也是操作的局部變量。
推而遠(yuǎn)之,這一切現(xiàn)象的本質(zhì)就是”它是否是明確的“。
仔細(xì)想想,就會(huì)發(fā)現(xiàn)不止dict不需要global,所有”明確的“東西都不需要global。因?yàn)閕nt類型str類型之類的不可變對(duì)象,每一次操作就重建新的對(duì)象,他們只有一種修改方法,即x = y, 恰好這種修改方法同時(shí)也是創(chuàng)建變量的方法,所以產(chǎn)生了歧義,不知道是要修改還是創(chuàng)建。而dict/list/對(duì)象等可變對(duì)象,操作不會(huì)重建對(duì)象,可以通過dict['x']=y或list.append()之類的來修改,跟創(chuàng)建變量不沖突,不產(chǎn)生歧義,所以都不用顯式global。
5.list的=和append/extend的區(qū)別

list_a = []
def a():
    list_a = [1]      ## 語句1
a()
print list_a    # []

print "======================"

list_b = []
def b():
    list_b.append(1)    ## 語句2
b()
print list_b    # [1]

因?yàn)?= 創(chuàng)建了局部變量,而 .append() 或者 .extend() 重用了全局變量。
可參考這個(gè)[https://blog.csdn.net/dream_allday/article/details/78767813]
一般可變對(duì)象的id變了,值也就不一樣了
6.5、陷阱:使用可變的默認(rèn)參數(shù)
我多次見到過如下的代碼:

def foo(a, b, c=[]):
# append to c
# do some more stuff
永遠(yuǎn)不要使用可變的默認(rèn)參數(shù),可以使用如下的代碼代替:

def foo(a, b, c=None):
    if c is None:
        c = []
    # append to c
    # do some more stuff
??與其解釋這個(gè)問題是什么,不如展示下使用可變默認(rèn)參數(shù)的影響:??

In[2]: def foo(a, b, c=[]):
...        c.append(a)
...        c.append(b)
...        print(c)
...
In[3]: foo(1, 1)
[1, 1]
In[4]: foo(1, 1)
[1, 1, 1, 1]
In[5]: foo(1, 1)
[1, 1, 1, 1, 1, 1]

同一個(gè)變量c在函數(shù)調(diào)用的每一次都被反復(fù)引用。這可能有一些意想不到的后果。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容