一位35歲老實(shí)程序員心魔因委屈而孕育,因失望而長大
730
2025-04-01
前言
python對象對于修改這個(gè)行為,大家的操作方式都是不一樣的。有些對象是可變類型,所以他就可以直接修改。其它的都是不可變類型,那我們要修改他時(shí)怎么辦呢,這個(gè)時(shí)候就新生成的一個(gè)對象,然后將變量名指向這個(gè)新對象,修改動作就完成了。關(guān)于可變類型與不可變類型的一個(gè)特點(diǎn),我們可以先看看一段奇怪的代碼
In [1]: a = 'a' In [2]: b = 'a' In [3]: a is b Out[3]: True In [4]: a == b Out[4]: True In [5]: c = [1] In [6]: d = [1] In [7]: c is d Out[7]: False In [8]: c == d Out[8]: True
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
In [1]: a = 'a'
In [2]: b = 'a'
In [3]: a is b
Out[3]: True
In [4]: a == b
Out[4]: True
In [5]: c = [1]
In [6]: d = [1]
In [7]: c is d
Out[7]: False
In [8]: c == d
Out[8]: True
你有沒有覺得,a b 明明都是不同的對象,但是使用a is b 的時(shí)候 竟然返回了true ,這里面就會深入到對象的別名,標(biāo)識與相等性,先說回到可變類型與不可變類型
分類
不可變類型
int
float
decimal
complex
bool
string
tuple
range
frozenset
bytes
可變類型
list
dict
set
bytearray
user-defined classes (unless specifically made immutable)
有個(gè)簡單的方式來區(qū)分這些類型,類似的容器類型的數(shù)據(jù)就是可變類型(list,set,dict)—我們就想像一個(gè)容器可以不停的注入內(nèi)容,其它的基本都是不可變的類型,這里有幾個(gè)特殊的
元組 tuple
frozenset
str
區(qū)分類型?有這個(gè)必要嗎?
當(dāng)然是顯然的,雖然我們在實(shí)際的工程環(huán)節(jié)都會圍繞整體的業(yè)務(wù)問題,很少去了解底層的原理,但是我們一旦涉及到優(yōu)化,涉及到底層的時(shí)候就很有必要了解技術(shù)細(xì)節(jié)。舉個(gè)例子,如何高效的拼接字符串,我想下面的代碼大部分人都寫過,包括我
In [13]: str_build = '' In [14]: for p in 'aaabbbccc': ...: str_build = str_build + p
1
2
3
4
In [13]: str_build = ''
In [14]: for p in 'aaabbbccc':
...:???? str_build = str_build + p
事實(shí)上,這樣的效率并不是很高。如上所言,我們知道str 是不可變類型,我們在拼接字符串的時(shí)候,實(shí)際上是生成了一個(gè)新的對象,然后在變量名指向他,隨著拼接的次數(shù)越來越多,我們生成對象的操作次數(shù)也會越來越多,這樣就很沒有這個(gè)必要(C# 里面的StringBuilder 就是為了解決字符串拼接的),那有效率的寫法是怎樣的呢
builder_list = [] for data in Container: builder_list.append(str(data)) "".join(builder_list) ### Another way is to use a list comprehension "".join([str(data) for data in Container]) ### or use the map function "".join(map(str, container))
1
2
3
4
5
6
7
8
9
10
11
12
builder_list = []
for data in container:
builder_list.append(str(data))
"".join(builder_list)
### Another way is to use a list comprehension
"".join([str(data) for data in container])
### or use the map function
"".join(map(str, container))
我們通過使用列表,可以輕松的在本身對象的基礎(chǔ)上修改內(nèi)容,不會生成新對象來處理操作,這樣就會節(jié)省內(nèi)存
另外的一個(gè)我們會遇到關(guān)于可變類型的一個(gè)坑
def my_function(param=[]): param.append("thing") return param my_function() # returns ["thing"] my_function() # returns ["thing", "thing"]
1
2
3
4
5
6
7
def my_function(param=[]):
param.append("thing")
return param
my_function() # returns ["thing"]
my_function() # returns ["thing", "thing"]
你會不會覺得,我去,不管我調(diào)用多少次,這丫不是應(yīng)該就返回一個(gè)[‘thing’]回來嗎?但是事實(shí)上你也看到了,因?yàn)榭勺儗ο笠恢倍紩猛欢蝺?nèi)容,我們在操作列表的時(shí)候都會對同一個(gè)列表操作,比如我們在函數(shù)體里面操作了一個(gè)set ,list ,或者 dict ,雖然我們沒有返回內(nèi)容,但是外部的內(nèi)容還是會變的,所以我們要記得,不要給可變對象做為參數(shù)的時(shí)候加上默認(rèn)值!
def my_function2(param=None): if param is None: param = [] param.append("thing") return param
1
2
3
4
5
6
def my_function2(param=None):
if param is None:
param = []
param.append("thing")
return param
結(jié)論
正確的區(qū)分可變類型與不可變類型,對于我們深入了解python是非常有幫助的,更多的關(guān)注技術(shù)細(xì)節(jié),才能更好的拔高我們的技術(shù)水平
番外
我們在前言里面有提到的那個(gè)奇怪的問題,很顯然,那是共享了字符串的字面量,這種Cpython里面一個(gè)優(yōu)化策略,叫駐留(interning).CPython 還會在小的整數(shù)上使用這個(gè)優(yōu)化措施,防止重復(fù)的創(chuàng)建”熱門“數(shù)字,比如0,-1,和42等等,但是CPython不會駐留所有的字符串和整數(shù)。比如如下的代碼
In [5]: c = 1 In [6]: d = 1 In [7]: id(c) Out[7]: 4297514912 In [8]: id(d) Out[8]: 4297514912 In [9]: e = 22569 In [10]: f = 22569 In [11]: e is f Out[11]: False In [12]: c is d Out[12]: True
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
In [5]: c = 1
In [6]: d = 1
In [7]: id(c)
Out[7]: 4297514912
In [8]: id(d)
Out[8]: 4297514912
In [9]: e = 22569
In [10]: f = 22569
In [11]: e is f
Out[11]: False
In [12]: c is d
Out[12]: True
所以千萬不要依賴字符串或者整數(shù)的駐留!比較字符串或者整數(shù)是否相等的時(shí),應(yīng)該使用== 而不是is. 駐留是python 解釋器內(nèi)部使用的一個(gè)特性。
Python
版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時(shí)內(nèi)刪除侵權(quán)內(nèi)容。
版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時(shí)內(nèi)刪除侵權(quán)內(nèi)容。