一猖闪、變量與對(duì)象
Python 中一切皆為對(duì)象,數(shù)字是對(duì)象吵护,列表是對(duì)象,函數(shù)也是對(duì)象雄坪,任何東西都是對(duì)象。
變量是對(duì)象的一個(gè)引用,又稱名字或者標(biāo)簽谒亦,對(duì)象的操作都是通過(guò)引用來(lái)完成的。
賦值操作
=
就是把一個(gè)引用綁定到一個(gè)對(duì)象上锁摔。例如,[]是一個(gè)空列表對(duì)象,賦值給變量a,變量 a 是該對(duì)象的一個(gè)引用芹枷。
a = []
a.append(1)
二、對(duì)象的可變性
- 不可變對(duì)象:對(duì)象所指向的內(nèi)存中的值不能被改變走芋。不可變對(duì)象賦值給變量后嗽上,由于變量指向的值不可變,如果改變變量(準(zhǔn)確的說(shuō)是引用)哲思,相當(dāng)于對(duì)變量進(jìn)行了重新賦值徘郭,指向了內(nèi)存中新的值胧后。
- 變量a引用了內(nèi)存中的對(duì)象:1
a = 1
- 對(duì)象1在內(nèi)存中的地址
print(a, id(1))
print(a, id(a))
1 4496995664
1 4496995664
- 變量a重新賦值眶痰,引用了內(nèi)存中的對(duì)象:2
a = 2
- 對(duì)象2在內(nèi)存中的地址
print(a, id(2))
print(a, id(a))
2 4496995696
2 4496995696
2. 可變對(duì)象:對(duì)象所指向的內(nèi)存中的值可以被改變条辟。如果改變變量(準(zhǔn)確的說(shuō)是引用),實(shí)際上只是對(duì)其所指的值進(jìn)行了變更氛赐,并沒(méi)有產(chǎn)生新的值,通俗點(diǎn)說(shuō)就是原地改變。
lt = [1, 2, 3]
print(id(lt))
4551719624
lt.append(100)
print(id(lt))
4551719624
- Python中,數(shù)值類型(int和float)、字符串str卜高、元組(tuple)都是不可變類型掺涛,而列表(list)矮燎、字典(dict)峡谊、集合(set)是可變類型。
三盾致、函數(shù)傳參
Python函數(shù)中,參數(shù)傳遞的全部都是對(duì)象的引用,本質(zhì)上是賦值操作蜓席,即把一個(gè)引用(變量)綁定到一個(gè)對(duì)象上。
參數(shù)是不可變對(duì)象時(shí),不會(huì)對(duì)對(duì)象進(jìn)行修改此洲,相當(dāng)于傳遞值衷畦。
參數(shù)是可變對(duì)象時(shí)暖释,會(huì)對(duì)對(duì)象進(jìn)行修改亮曹,相當(dāng)傳遞引用。
在定義函數(shù)時(shí)板熊,要注意函數(shù)的參數(shù)喘沿,傳遞的是值還是引用摹恨,特別是對(duì)于 默認(rèn)參數(shù) 寝凌,很容易導(dǎo)致潛在的bug较木。
四伐债、函數(shù)的默認(rèn)參數(shù)
- 默認(rèn)參數(shù)是傳遞值時(shí)虹蒋,僅僅在函數(shù)定義的時(shí)候賦值一次晃虫。
x = 8
def func(a, b=x):
return a, b
print(func(1))
(1, 8)
x = 20
print(func(1))
(1, 8)
- 示例中,默認(rèn)參數(shù)
b
賦值為x
型酥,x
為不可變對(duì)象字符串8
讥蟆,當(dāng)對(duì)x
重新賦值為20后,調(diào)用函數(shù)時(shí)纺阔,默認(rèn)參數(shù)b
的值仍然為8
瘸彤。 - 默認(rèn)參數(shù)的值,通常應(yīng)該是不可變的對(duì)象笛钝,比如None质况、True愕宋、False、數(shù)字或字符串结榄。
- 默認(rèn)參數(shù)是傳遞引用時(shí)中贝,通常為空,比如空列表
[]
或空集合{}
潭陪,但在定義函數(shù)時(shí)雄妥,盡量設(shè)置為None,而不要讓參數(shù)直接等于空列表或空集合依溯。
def fun(a, b = []):
return b
f = fun(1)
print(f)
[]
f.append(100)
print(f)
[100]
- 像上述示例中老厌,如果設(shè)置默認(rèn)參數(shù)
b = []
,因?yàn)槭强勺儗?duì)象黎炉,當(dāng)默認(rèn)參數(shù)b
的對(duì)象枝秤,在其他地方被修改后,下次調(diào)用這個(gè)函數(shù)時(shí)其默認(rèn)參數(shù)b
已不再是空列表慷嗜。 - 特殊情況下淀弹,比如在for循環(huán)中,調(diào)用默認(rèn)參數(shù)為空列表
[]
或空集合{}
的函數(shù)庆械,可以循環(huán)累積迭代結(jié)果薇溃。
五、匿名函數(shù)捕獲參數(shù)值
-
lambda
表達(dá)式中的參數(shù)x
是一個(gè)自由變量缭乘, 是在執(zhí)行時(shí)賦值(綁定)沐序,而不是定義時(shí)賦值(綁定),即lambda
表達(dá)式中的參數(shù)x
是執(zhí)行時(shí)的值堕绩,這與函數(shù)的 默認(rèn)參數(shù) 賦值不相同策幼。
x = 10
a = lambda y: y + x
x = 20
print(a(10))
30
?示例中,調(diào)用a(10)
時(shí)奴紧,x
取值為20
特姐,而不是定義時(shí)的10
。
- 如果想讓匿名函數(shù)黍氮,在定義時(shí)就捕獲到參數(shù)值唐含,將參數(shù)
x
定義成默認(rèn)參數(shù)即可,例如:
z = 10
a = lambda x, z=z: x + z
print(a(2))
12
z = 7
print(a(2))
12
?示例中沫浆,對(duì)變量z
重新賦值為7
觉壶,再次調(diào)用函數(shù)a(2)
時(shí),匿名函數(shù)的參數(shù)z
的值仍
?然為定義時(shí)的10
件缸,而不是7
铜靶。