python中單下劃線與雙下劃線的區(qū)別及說(shuō)明
Python用下劃線作為前綴和后綴指定特殊變量和定義方法,主要有如下四種形式:
- 單下劃線(_)
- 名稱前的單下劃線(如:_name)
- 名稱前的雙下劃線(如:__name)
- 名稱前后的雙下劃線(如:__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è)變量定義名稱,這時(shí)就可以用單下劃線作為臨時(shí)性的變量。
比如對(duì)for循環(huán)語(yǔ)句遍歷的結(jié)果元素并不感興趣,此時(shí)就可以用單下劃線表示。
# _ 這個(gè)變量在后面不會(huì)用到
for _ in range(5):
print("Python")名稱前的單下劃線(如:_name)
當(dāng)在屬性和方法前面加上單下劃線“_”,用于指定屬性和方法是“私有”的。
但是Python不像Java一樣具有私有屬性、方法、類,在屬性和方法之前加單下劃線,只是代表該屬性、方法、類只能在內(nèi)部使用,是API中非公開的部分。
如果用fromimport * 和 fromimport * 時(shí),這些屬性、方法、類將不被導(dǎo)入。
# Test.py 文件
#普通屬性
value="Java"
#單下劃線屬性
_otherValue="Python"
#普通方法
def method():
print("我是普通方法")
#單下劃線方法
def _otherMethod():
print("我是單下劃線方法")
#普通類
class PClass(object):
def __init__(self):
print("普通類的初始化")
#單下劃線類
class _WClass(object):
def __init__(self):
print("單下劃線類的初始化")將上述的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()
普通類的初始化
>>> w=_WClass()
Traceback (most recent call last):
File "<pyshell#8>", line 1, in <module>
w=_WClass()
NameError: name '_WClass' is not defined
從上面的結(jié)果可以看出,不管是屬性、方法和類,只要名稱前面加了單下劃線,都不能導(dǎo)出。
如果對(duì)程序進(jìn)行修改,將在開頭加入__all__,結(jié)果會(huì)是如何?
# Test.py 文件
#將普通屬性、單下劃線的屬性、方法、和類加入__all__列表
__all__=["value","_otherValue","_otherMethod","_WClass"]
#普通屬性
value="Java"
#單下劃線屬性
_otherValue="Python"
#普通方法
def method():
print("我是普通方法")
#單下劃線方法
def _otherMethod():
print("我是單下劃線方法")
#普通類
class PClass(object):
def __init__(self):
print("普通類的初始化")
#單下劃線類
class _WClass(object):
def __init__(self):
print("單下劃線類的初始化")將上述修改過(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()
單下劃線類的初始化__all__是一個(gè)字符串列表,不管是普通的還是單下劃線的屬性、方法和類,都將導(dǎo)出來(lái),使用其他不在這個(gè)字符列表上的屬性、方法和類,都會(huì)報(bào)未定義的錯(cuò)誤。
不管是屬性、方法和類,只要名稱前面加了單下劃線,都不能導(dǎo)入。
除非是模塊或包中的“__all__”列表顯式地包含了它們。
名稱前的雙下劃線(如:__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è)類,這個(gè)類有三個(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類沒(méi)有這個(gè)方法屬性的錯(cuò)誤。
那如何去調(diào)用以雙下劃線開頭的方法和屬性?
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)用以雙下劃線開頭的方法和屬性,只要以“類名_方法(屬性)”的形式就可以實(shí)現(xiàn)方法或者屬性的訪問(wèn)了。類前面是單下劃線,類名后面是雙下劃線,然后再加上方法或者屬性。但是并不建議調(diào)用,因?yàn)檫@是Python內(nèi)部進(jìn)行調(diào)用的形式。
回答完第一個(gè)問(wèn)題,我們看看第二個(gè)問(wèn)題,Python這樣設(shè)計(jì)的目的是什么?
有很多人認(rèn)為,Python以雙下劃線開頭的方法和屬性表示私有的方法和屬性,實(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è)類,一個(gè)是AMethod類,另外一個(gè)是繼承了AMethod類的BMethod類。
在AMethod類中,定義了兩個(gè)方法,一個(gè)是以雙下劃線開頭的__method方法,另外一個(gè)是普通方法。
在BMethod類中,重寫了AMethod類中的__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類的__method方法,而這個(gè)設(shè)計(jì)的實(shí)際目的是為了避免父類的方法被子類輕易的覆蓋。
名稱前后的雙下劃線(如:__ init __)
在Python類中,我們可以常??吹筋愃朴?ldquo;__ init ___”的方法,這表示在Python內(nèi)部調(diào)用的方法,一般不建議在程序中調(diào)用。
比如,當(dāng)調(diào)用len()方法時(shí),實(shí)際上調(diào)用了 Python中內(nèi)部的 ___len ___方法,雖然不建議調(diào)用這種以雙下劃線開頭以及結(jié)尾的方法,但是可以對(duì)這些方法進(jìn)行重寫。
比如下面的例子:
class Number(object):
def __init__(self, number):
self.number = number
def __add__(self, number):
# 重寫方法,返回兩個(gè)數(shù)的差值
return self.number - number
def __sub__(self, number):
# 重寫方法,返回兩個(gè)數(shù)的和
return self.number + number
def __str__(self):
# 重寫方法,返回字符串
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è)變量。
名稱前的單下劃線:只能在內(nèi)部使用,是API中非公開的部分,不能被import * 和 fromimport *導(dǎo)入程序中,除非在all列表中包含了以單下劃線開頭的屬性、方法以及類。
名稱前的雙下劃線:以雙下劃線開頭的屬性、方法表示避免父類的屬性和方法被子類輕易的覆蓋,一般不建議這樣定義屬性和方法,除非你自己將要做什么。
名稱前后的雙下劃線:這類方法是Python內(nèi)部定義的方法,你可以重寫這些方法,這樣Python就可以調(diào)用這個(gè)重寫的方法以及利用操作符。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
YOLOv5車牌識(shí)別實(shí)戰(zhàn)教程(一)引言與準(zhǔn)備工作
這篇文章主要介紹了YOLOv5車牌識(shí)別實(shí)戰(zhàn)教程(一)引言與準(zhǔn)備工作,在這個(gè)教程中,我們將一步步教你如何使用YOLOv5進(jìn)行車牌識(shí)別,幫助你快速掌握YOLOv5車牌識(shí)別技能,需要的朋友可以參考下2023-04-04
一文詳解如何使用Python自動(dòng)調(diào)整Excel行高和列寬
在 Excel 數(shù)據(jù)處理和報(bào)告編制過(guò)程中,確保單元格內(nèi)容完整顯示是常見需求,本文將介紹如何使用 Free Spire.XLS for Python 來(lái)實(shí)現(xiàn)自動(dòng)調(diào)整 Excel 行高和列寬,有需要的小伙伴可以了解下2025-10-10
Python中的錯(cuò)誤處理與調(diào)試技巧分享
在軟件開發(fā)過(guò)程中,錯(cuò)誤是不可避免的,無(wú)論是在開發(fā)初期還是在項(xiàng)目后期,程序都可能會(huì)遇到各種各樣的錯(cuò)誤,本文將深入探討 Python 中的錯(cuò)誤處理機(jī)制、常見錯(cuò)誤類型及其處理方法,并介紹一些實(shí)用的調(diào)試技巧,以提高開發(fā)效率和代碼質(zhì)量,需要的朋友可以參考下2025-01-01
django-simple-captcha多種驗(yàn)證碼的實(shí)現(xiàn)方法
本文介紹了如何在Django項(xiàng)目中配置和使用不同類型的驗(yàn)證碼,包括數(shù)字驗(yàn)證碼、字母驗(yàn)證碼和算術(shù)驗(yàn)證碼,每種驗(yàn)證碼結(jié)合實(shí)例代碼給大家介紹得非常詳細(xì),感興趣的朋友跟隨小編一起看看吧2024-12-12
pandas中DataFrame修改index、columns名的方法示例
這篇文章主要介紹了pandas中DataFrame修改index、columns名的方法示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-08-08
使用Python的SymPy庫(kù)解決數(shù)學(xué)運(yùn)算問(wèn)題的方法
這篇文章主要介紹了使用Python的SymPy庫(kù)解決數(shù)學(xué)運(yùn)算問(wèn)題的方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2019-03-03

