Python的高級特性1:容易忽略的不可變類型


python中有一些容易忽略的不可變類型(str,integer,tuple,None)

#錯誤演示
In [45]: def demo(lst=[]): ....: lst.append("hello") ....: return lst ....: In [46]: demo() Out[46]: ['hello'] In [47]: demo() Out[47]: ['hello', 'hello']

廖雪峰的python教程有提到這一塊,但並沒有太細致。在這里,由於lst是一個可變參數,而demo在初始化時lst參數指向一個[]的內存空間,之后每一次調用,[]這個內存空間都append一個“hello”,而由於lst依然指向這個內存空間,所以就會看到demo函數調用的奇怪現象,解決問題的辦法就是引入不可變類型。

#正確演示

In [54]: def demo(lst=None):
   ....:     lst=[]
   ....:     lst.append("hello")
   ....:     return lst
   ....: 

In [55]: demo()
Out[55]: ['hello']

In [56]: demo()
Out[56]: ['hello']

在正確演示中,將lst初始化為None,這樣lst就是一個不可變參數,但是不能直接對lst直接使用append,因為只有list才有append方法,因此需要將lst進行真正的初始化:lst=[]

可變類型和不可變類型是一個很容易忽略的知識點,在這里深入進行研究,下面例舉常見的不可變類型和可變類型。

  • 不可變(mutable)類型:int, long, float, string, tuple, frozenset
  • 可變類型(immutable)類型:list, dict

Python中所有變量都是值的引用,也就說變量通過綁定的方式指向其值。 而這里說的不可變指的是值的不可變。 對於不可變類型的變量,如果要更改變量,則會創建一個新值,把變量綁定到新值上,而舊值如果沒有被引用就等待垃圾回收。下面用int和list分別作為代表進行講解。

#不可變類型

In [31]: id(1),id(2)
Out[31]: (4477999936, 4477999968)

In [32]: a = 1

In [33]: id(a)
Out[33]: 4477999936

In [34]: #當a賦一個新值時,變量a會綁定到新值上

In [35]: a = 3

In [36]: id(a)
Out[36]: 4478000000

#可變類型

In [38]: lst = [0]

In [39]: id(lst)
Out[39]: 4493976328

In [40]: lst = [0,1]

In [41]: id(lst)
Out[41]: 4499600328

ps:表面上看可變類型,python似乎實現了不同類型的管理方式,其實不是的。其實lst代表地址,它引用的lst[0],lst[1]的內存地址其實是變了的,因為lst[i]就是int(此處),而int就是不可變類型。

另外,我還想延伸一下關於__new__的用法。為什么要放在這里說,待會看了這個例子就會明白。

class Word(str):
    def __new__(cls, word):
        word = word.replace(" ","")
        return str.__new__(cls,word)

    def __init__(self,word):
        self.word = word

def __eq__(self, other): return len(self)==len(other)

def main(): a=Word("foorrrdd ") b=Word("sswwss ") print a==b
if __name__ == '__main__': main()

在這段代碼里,可以看到Word類繼承自str,str是一個不可變類型,因此需要使用到__new__這個魔術方法,在這里對word這個形參進行了預處理,然后預處理后的形參word會傳遞給__init__。由於此例此種情形中,a,b指向的是不同的內存空間,即使不用__new__也不會因為實參的傳入導致上面例子出現不斷追加的情況,但顯然這會是一種更為安全的寫法。

 

(ps:我不是很確定None是不是一個不可變類型,這篇文章只是個人的理解,如果有誤,懇請指正。)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM