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

