python中單下劃線與雙下劃線的區(qū)別及說(shuō)明
Python用下劃線作為前綴和后綴指定特殊變量和定義方法,主要有如下四種形式:
- 單下劃線(_)
- 名稱(chēng)前的單下劃線(如:_name)
- 名稱(chēng)前的雙下劃線(如:__name)
- 名稱(chēng)前后的雙下劃線(如:__init__)
單下劃線(_)
只有單劃線的情況,主要有兩種使用場(chǎng)景:
1、在交互式解釋器中,單下劃線“_”代表的是上一條執(zhí)行語(yǔ)句的結(jié)果。
如果單下劃線前面沒(méi)有語(yǔ)句執(zhí)行,交互式解釋器將會(huì)報(bào)單下劃線沒(méi)有定義的錯(cuò)誤。
也可以對(duì)單下劃線進(jìn)行賦值操作,這時(shí)單下劃線代表賦值的結(jié)果。
但是一般不建議對(duì)單下劃線進(jìn)行賦值操作,因?yàn)閱蜗聞澗€內(nèi)建標(biāo)識(shí)符。
>>> _ Traceback (most recent call last): File "<pyshell#0>", line 1, in <module> _ NameError: name '_' is not defined >>> "python" 'python' >>> _ 'python' >>> _="Java" >>> _ 'Java' >>>
2、單下劃線“_”還可以作為特殊的臨時(shí)變量。
如果一個(gè)變量在后面不會(huì)再用到,并且不想給這個(gè)變量定義名稱(chēng),這時(shí)就可以用單下劃線作為臨時(shí)性的變量。
比如對(duì)for循環(huán)語(yǔ)句遍歷的結(jié)果元素并不感興趣,此時(shí)就可以用單下劃線表示。
# _ 這個(gè)變量在后面不會(huì)用到 for _ in range(5): print("Python")
名稱(chēng)前的單下劃線(如:_name)
當(dāng)在屬性和方法前面加上單下劃線“_”,用于指定屬性和方法是“私有”的。
但是Python不像Java一樣具有私有屬性、方法、類(lèi),在屬性和方法之前加單下劃線,只是代表該屬性、方法、類(lèi)只能在內(nèi)部使用,是API中非公開(kāi)的部分。
如果用fromimport * 和 fromimport * 時(shí),這些屬性、方法、類(lèi)將不被導(dǎo)入。
# Test.py 文件 #普通屬性 value="Java" #單下劃線屬性 _otherValue="Python" #普通方法 def method(): print("我是普通方法") #單下劃線方法 def _otherMethod(): print("我是單下劃線方法") #普通類(lèi) class PClass(object): def __init__(self): print("普通類(lèi)的初始化") #單下劃線類(lèi) class _WClass(object): def __init__(self): print("單下劃線類(lèi)的初始化")
將上述的Test.py文件導(dǎo)入,進(jìn)行測(cè)試。
>>> from Test import * >>> value 'Java' >>> _otherValue Traceback (most recent call last): File "<pyshell#4>", line 1, in <module> _otherValue NameError: name '_otherValue' is not defined >>> method() 我是普通方法 >>> _otherMethod() Traceback (most recent call last): File "<pyshell#6>", line 1, in <module> _otherMethod() NameError: name '_otherMethod' is not defined >>> p=PClass() 普通類(lèi)的初始化 >>> w=_WClass() Traceback (most recent call last): File "<pyshell#8>", line 1, in <module> w=_WClass() NameError: name '_WClass' is not defined
從上面的結(jié)果可以看出,不管是屬性、方法和類(lèi),只要名稱(chēng)前面加了單下劃線,都不能導(dǎo)出。
如果對(duì)程序進(jìn)行修改,將在開(kāi)頭加入__all__,結(jié)果會(huì)是如何?
# Test.py 文件 #將普通屬性、單下劃線的屬性、方法、和類(lèi)加入__all__列表 __all__=["value","_otherValue","_otherMethod","_WClass"] #普通屬性 value="Java" #單下劃線屬性 _otherValue="Python" #普通方法 def method(): print("我是普通方法") #單下劃線方法 def _otherMethod(): print("我是單下劃線方法") #普通類(lèi) class PClass(object): def __init__(self): print("普通類(lèi)的初始化") #單下劃線類(lèi) class _WClass(object): def __init__(self): print("單下劃線類(lèi)的初始化")
將上述修改過(guò)的Test.py文件導(dǎo)入,進(jìn)行測(cè)試。
>>> from Test import * >>> value 'Java' >>> _otherValue 'Python' >>> method() Traceback (most recent call last): File "<pyshell#4>", line 1, in <module> method() NameError: name 'method' is not defined >>> _otherMethod() 我是單下劃線方法 >>> p=PClass() Traceback (most recent call last): File "<pyshell#6>", line 1, in <module> p=PClass() NameError: name 'PClass' is not defined >>> w= _WClass() 單下劃線類(lèi)的初始化
__all__是一個(gè)字符串列表,不管是普通的還是單下劃線的屬性、方法和類(lèi),都將導(dǎo)出來(lái),使用其他不在這個(gè)字符列表上的屬性、方法和類(lèi),都會(huì)報(bào)未定義的錯(cuò)誤。
不管是屬性、方法和類(lèi),只要名稱(chēng)前面加了單下劃線,都不能導(dǎo)入。
除非是模塊或包中的“__all__”列表顯式地包含了它們。
名稱(chēng)前的雙下劃線(如:__name)
我們先看看下面的程序:
class Method(object): # 構(gòu)造器方法 def __init__(self, name): # 雙下劃線屬性 self.__name = name # 普通方法 def sayhello(self): print("Method say hello!") # 雙下劃線方法 def __sayhi(self): print("Method say hi!") # 初始化Method m = Method("Python") # 調(diào)用sayhello方法 m.sayhello() # 調(diào)用sayhi方法 m.__sayhi() # 輸出屬性__name print(m.__name)
上面的程序定義了一個(gè)類(lèi),這個(gè)類(lèi)有三個(gè)方法,一個(gè)構(gòu)造器方法,一個(gè)普通方法,一個(gè)雙下劃線方法,以及包括一個(gè)雙下劃線的屬性。
上面的結(jié)果輸出的是什么?
很多讀者可能認(rèn)為輸出的結(jié)果如下:
Method say hello!
Method say hi!
Python
那么恭喜你,上面的輸出結(jié)果是錯(cuò)誤的,實(shí)際輸出的結(jié)果為:
Method say hello!
Traceback (most recent call last):
File "<encoding error>", line 18, in <module>
AttributeError: 'Method' object has no attribute '__sayhi'
實(shí)際上,當(dāng)對(duì)象調(diào)用__sayhi()方法時(shí),將會(huì)報(bào)Method類(lèi)沒(méi)有這個(gè)方法屬性的錯(cuò)誤。
那如何去調(diào)用以雙下劃線開(kāi)頭的方法和屬性?
Python這樣設(shè)計(jì)的目的是什么?
首先回答第一個(gè)問(wèn)題,讀者看完下面的程序就知道怎么調(diào)用了。
class Method(object): def __init__(self, name): self.__name = name def sayhello(self): print("Method say hello!") def __sayhi(self): print("Method say hi!") # 初始化Method m = Method("Python") # 調(diào)用sayhello方法 m.sayhello() # 調(diào)用sayhi方法 #m.__sayhi() m._Method__sayhi() # 輸出屬性__name #print(m.__name) print(m._Method__name)
輸出結(jié)果如下:
Method say hello!
Method say hi!
Python
我們從上面的程序中可以很清楚的看到,如果要調(diào)用以雙下劃線開(kāi)頭的方法和屬性,只要以“類(lèi)名_方法(屬性)”的形式就可以實(shí)現(xiàn)方法或者屬性的訪問(wèn)了。類(lèi)前面是單下劃線,類(lèi)名后面是雙下劃線,然后再加上方法或者屬性。但是并不建議調(diào)用,因?yàn)檫@是Python內(nèi)部進(jìn)行調(diào)用的形式。
回答完第一個(gè)問(wèn)題,我們看看第二個(gè)問(wèn)題,Python這樣設(shè)計(jì)的目的是什么?
有很多人認(rèn)為,Python以雙下劃線開(kāi)頭的方法和屬性表示私有的方法和屬性,實(shí)際上這樣的理解不太準(zhǔn)確,也不能說(shuō)完全錯(cuò)誤的。
但是這并不是Python設(shè)計(jì)的目的和初衷,我們先看看下面一段程序和程序運(yùn)行結(jié)果:
class AMethod(object): def __method(self): print("__method in class Amethod!") def method(self): self.__method() print("anthod method in class AMethod!") class BMethod(AMethod): def __method(self): print("__method in class Bmethod!") if __name__=="__main__": print("調(diào)用AMethod的method方法") a = AMethod() a.method() print("調(diào)用BMethod的method方法") b = BMethod() b.method()
上面的程序定義了兩個(gè)類(lèi),一個(gè)是AMethod類(lèi),另外一個(gè)是繼承了AMethod類(lèi)的BMethod類(lèi)。
在AMethod類(lèi)中,定義了兩個(gè)方法,一個(gè)是以雙下劃線開(kāi)頭的__method方法,另外一個(gè)是普通方法。
在BMethod類(lèi)中,重寫(xiě)了AMethod類(lèi)中的__method方法。
程序運(yùn)行結(jié)果:
調(diào)用AMethod的method方法
__method in class Amethod!
anthod method in class AMethod!
調(diào)用BMethod的method方法
__method in class Amethod!
anthod method in class AMethod!
運(yùn)行結(jié)果并不是我們想要的結(jié)果,b.method()并沒(méi)有調(diào)用BMethod類(lèi)的__method方法,而這個(gè)設(shè)計(jì)的實(shí)際目的是為了避免父類(lèi)的方法被子類(lèi)輕易的覆蓋。
名稱(chēng)前后的雙下劃線(如:__ init __)
在Python類(lèi)中,我們可以常??吹筋?lèi)似于“__ init ___”的方法,這表示在Python內(nèi)部調(diào)用的方法,一般不建議在程序中調(diào)用。
比如,當(dāng)調(diào)用len()方法時(shí),實(shí)際上調(diào)用了 Python中內(nèi)部的 ___len ___方法,雖然不建議調(diào)用這種以雙下劃線開(kāi)頭以及結(jié)尾的方法,但是可以對(duì)這些方法進(jìn)行重寫(xiě)。
比如下面的例子:
class Number(object): def __init__(self, number): self.number = number def __add__(self, number): # 重寫(xiě)方法,返回兩個(gè)數(shù)的差值 return self.number - number def __sub__(self, number): # 重寫(xiě)方法,返回兩個(gè)數(shù)的和 return self.number + number def __str__(self): # 重寫(xiě)方法,返回字符串 return str(self.number) num = Number(100) print(num) # 100 調(diào)用了__str__方法 print(num+50) # 50 + 調(diào)用了__add__方法 print(num-20) # 120 -調(diào)用了__sub__方法
相信看了上面所有對(duì)Python中下劃線作用的講解,完全能夠理解上述四種下劃線所表示的意義。最后將對(duì)上面的,進(jìn)行總結(jié)。
總結(jié)
單下劃線(_): 在交互解釋器中,表示上一條語(yǔ)句執(zhí)行輸出的結(jié)果。另外,單下劃線還可以作為特殊的臨時(shí)變量,表示在后面將不會(huì)在用到這個(gè)變量。
名稱(chēng)前的單下劃線:只能在內(nèi)部使用,是API中非公開(kāi)的部分,不能被import * 和 fromimport *導(dǎo)入程序中,除非在all列表中包含了以單下劃線開(kāi)頭的屬性、方法以及類(lèi)。
名稱(chēng)前的雙下劃線:以雙下劃線開(kāi)頭的屬性、方法表示避免父類(lèi)的屬性和方法被子類(lèi)輕易的覆蓋,一般不建議這樣定義屬性和方法,除非你自己將要做什么。
名稱(chēng)前后的雙下劃線:這類(lèi)方法是Python內(nèi)部定義的方法,你可以重寫(xiě)這些方法,這樣Python就可以調(diào)用這個(gè)重寫(xiě)的方法以及利用操作符。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Python常見(jiàn)報(bào)錯(cuò)解決方案總結(jié)(新手拯救指南)
我們?cè)偈褂胮ython難免會(huì)出現(xiàn)各種各樣的報(bào)錯(cuò),下面這篇文章主要給大家介紹了關(guān)于Python常見(jiàn)報(bào)錯(cuò)解決方案的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-05-05python游戲庫(kù)pygame經(jīng)典教程(推薦!)
Python Pygame是一款專(zhuān)門(mén)為開(kāi)發(fā)和設(shè)計(jì) 2D 電子游戲而生的軟件包,是入門(mén)級(jí)游戲開(kāi)發(fā)庫(kù),下面這篇文章主要給大家介紹了python游戲庫(kù)pygame經(jīng)典教程的相關(guān)資料,需要的朋友可以參考下2022-12-12Python 函數(shù)繪圖及函數(shù)圖像微分與積分
今天小編就為大家分享一篇Python 函數(shù)繪圖及函數(shù)圖像微分與積分,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-11-11python進(jìn)程池的簡(jiǎn)單實(shí)現(xiàn)
本文主要介紹了python進(jìn)程池的簡(jiǎn)單實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-03-03Python實(shí)現(xiàn)圖書(shū)管理系統(tǒng)設(shè)計(jì)
這篇文章主要為大家詳細(xì)介紹了Python實(shí)現(xiàn)圖書(shū)管理系統(tǒng)設(shè)計(jì),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03Python數(shù)據(jù)分析中Groupby用法之通過(guò)字典或Series進(jìn)行分組的實(shí)例
下面小編就為大家分享一篇Python數(shù)據(jù)分析中Groupby用法之通過(guò)字典或Series進(jìn)行分組的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2017-12-12Python使用pyppeteer進(jìn)行網(wǎng)頁(yè)截圖并發(fā)送機(jī)器人實(shí)例
這篇文章主要介紹了Python使用pyppeteer進(jìn)行網(wǎng)頁(yè)截圖并發(fā)送機(jī)器人實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-04-04