【Python】單下劃線與雙下劃線的區別

lhrbest發表於2019-01-24


Python 用下劃線作為字首和字尾指定特殊變數和定義方法,主要有如下四種形式:

單下劃線( _

名稱前的單下劃線(如: _name

名稱前的雙下劃線(如: __name

名稱前後的雙下劃線(如 :__init__

(一) 單下劃線( _

只有單 劃線的情況,主要有兩種使用場景:

1 、在互動式直譯器中,單下劃線“ _ ”代表的是上一條執行語句的結果。如果單下劃線前面沒有語句執行, 那麼 互動式直譯器將會報單下劃線沒有定義的錯誤。也可以對單下劃線進行賦值操作,這時單下劃線代表賦值的結果。但是一般不建議對單下劃線進行賦值操作,因為單下劃線內建識別符號。

>>> _

Traceback (most recent call last):

  File "<pyshell#0>", line 1, in <module>

    _

NameError: name '_' is not defined

>>> "python"

'python'

>>> _

'python'

>>> _="Java"

>>> _

'Java'

>>>

2 、單下劃線“ _ ”還可以作為特殊的臨時變數。如果一個變數在後面不會再用到,並且不想給這個變數定義名稱, 那麼 這時就可以用單下劃線作為臨時性的變數。 例如, for 迴圈語句遍歷的結果元素並不感興趣,此時就可以用單下劃線表示。

# _ 這個變數在後面不會用到

for _ in range(5):

    print("Python")

(二) 名稱前的單下劃線(如: _name

當在屬性和方法前面加上單下劃線 _ ”,用於指定屬性和方法是“私有”的。但是 Python 不像 Java 一樣具有私有屬性、方法、類,在屬性和方法之前加單下劃線,只是代表該屬性、方法、類只能在內部使用,是 API 中非公開的部分。如果用 from <module> import *   from <package> import * 時,這些屬性、方法、類將不被匯入。

# 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 檔案匯入,進行測試。

>>> 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

從上面的結果可以看出,不管是屬性、方法和類,只要 名稱前面加了單下劃線,都不能匯出。如果對程式 Test.py 進行修改,在 檔案 開頭加入 __all__ 結果會是如何?

# 將普通屬性、單下劃線的屬性、方法、和類加入 __all__ 列表

__all__=["value" "_otherValue","_otherMethod","_WClass"]

修改後繼續測試:

>>> 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__ 是一個字串列表,不管是普通的還是單下劃線的屬性、方法和類,都將匯出來,使用其他不在這個字元列表上的屬性、方法和類,都會報未定義的錯誤。不管是屬性、方法和類,只要名稱前面加了單下劃線,都不能匯入。除非是模組或包中的“ __all__ ”列表顯式地包含了它們。

(三) 名稱前的雙下劃線(如: __name

先看看下面的程式:

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")

# 呼叫 sayhello 方法

m.sayhello()

# 呼叫 sayhi 方法

m.__sayhi()

# 輸出屬性 __name

print(m.__name)

上面的程式定義了一個類,這個類有三個方法,一個構造器方法,一個普通方法,一個雙下劃線方法,以及包括一個雙下劃線的屬性。上面 輸出結果

Method say hello!

Traceback (most recent call last):

  File "<encoding error>", line 18, in <module>

AttributeError: 'Method' object has no attribute '__sayhi'

實際上,當物件呼叫 __sayhi() 方法時,將會報 Method 類沒有這個方法屬性的錯誤。那如何去呼叫以雙下劃線開頭的方法和屬性? Python 這樣設計的目的是什麼?

首先回答第一個問題,讀者看完下面的程式就知道怎麼呼叫了。

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")

# 呼叫 sayhello 方法

m.sayhello()

# 呼叫 sayhi 方法

#m.__sayhi()

m._Method__sayhi()

# 輸出屬性 __name

#print(m.__name)

print(m._Method__name)

輸出結果如下:

Method say hello!

Method say hi!

Python

從上面的程式中可以很清楚的看到,如果要呼叫以雙下劃線開頭的方法和屬性,只要以 _ 類名 __ 方法(屬性)”的形式就可以實現方法或者屬性的訪問了。類前面是單下劃線,類名後面是雙下劃線,然後再加上方法或者屬性。但是並不建議呼叫,因為這是 Python 內部進行呼叫的形式。

回答完第一個問題,我們看看第二個問題, Python 這樣設計的目的是什麼?

有很多人認為, Python 以雙下劃線開頭的方法和屬性表示私有的方法和屬性,實際上這樣的理解不太準確,也不能說完全錯誤的。但是這並不是 Python 設計的目的和初衷,我們先看看下面一段程式和程式執行結果 :

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(" 呼叫 AMethod method 方法 ")

    a = AMethod()

    a.method()

 

    print(" 呼叫 BMethod method 方法 ")

    b = BMethod()

    b.method()

上面的程式定義了兩個類,一個是 AMethod 類,另外一個是繼承了 AMethod 類的 BMethod 類。在 AMethod 類中,定義了兩個方法,一個是以雙下劃線開頭的 __method 方法,另外一個是普通方法。在 BMethod 類中,重寫了 AMethod 類中的 __method 方法。

程式執行結果:

呼叫 AMethod method 方法

__method in class Amethod!

anthod method in class AMethod!

呼叫 BMethod method 方法

__method in class Amethod!

anthod method in class AMethod!

執行結果並不是我們想要的結果, b.method() 並沒有呼叫 BMethod 類的 __method 方法,而這個設計的實際目的是為了避免父類的方法被子類輕易的覆蓋。

(四) 名稱前後的雙下劃線(如 __init__

Python 類中,可以常常看到類似於“ __init__ ”的方法,這表示在 Python 內部呼叫的方法,一般不建議在程式中呼叫。比如,當呼叫 len() 方法時,實際上呼叫了 Python 中內部的 __len__ 方法,雖然不建議呼叫這種以雙下劃線開頭以及結尾的方法,但是可以對這些方法進行重寫。比如下面的例子:

class Number(object):

 

    def __init__(self, number):

        self.number = number

 

    def __add__(self, number):

        # 重寫方法,返回兩個數的差值

        return self.number - number

 

    def __sub__(self, number):

        # 重寫方法,返回兩個數的和

        return self.number + number

 

    def __str__(self):

        # 重寫方法,返回字串

        return str(self.number)

 

num = Number(100)

print(num) # 100 呼叫了 __str__ 方法

print(num+50) # 50 + 呼叫了 __add__ 方法

print(num-20) # 120 - 呼叫了 __sub__ 方法

相信看了上面所有對 Python 中下劃線作用的講解,完全能夠理解上述四種下劃線所表示的意義。最後將對上面的,進行總結。

(五) 總結

單下劃線( _ 在互動直譯器中,表示上一條語句執行輸出的結果。另外,單下劃線還可以作為特殊的臨時變數,表示在後面將不會在用到這個變數。

名稱前的單下劃線:只能在內部使用,是 API 中非公開的部分,不能被 <module>import   * from   <package>   import   * 匯入程式中,除非在 __all__ 列表中包含了以單下劃線開頭的屬性、方法以及類。

名稱前的雙下劃線:以雙下劃線開頭的屬性、方法表示避免父類的屬性和方法被子類輕易的覆蓋,一般不建議這樣定義屬性和方法,除非你自己將要做什麼。

名稱前後的雙下劃線:這類方法是 Python 內部定義的方法,可以重寫這些方法,這樣 Python 就可以呼叫這個重寫的方法以及利用運算子。

 




About Me

........................................................................................................................

● 本文作者:小麥苗,部分內容整理自網路,若有侵權請聯絡小麥苗刪除

● 本文在itpub( http://blog.itpub.net/26736162 )、部落格園( http://www.cnblogs.com/lhrbest )和個人weixin公眾號( xiaomaimiaolhr )上有同步更新

● 本文itpub地址: http://blog.itpub.net/26736162

● 本文部落格園地址: http://www.cnblogs.com/lhrbest

● 本文pdf版、個人簡介及小麥苗雲盤地址: http://blog.itpub.net/26736162/viewspace-1624453/

● 資料庫筆試面試題庫及解答: http://blog.itpub.net/26736162/viewspace-2134706/

● DBA寶典今日頭條號地址:

........................................................................................................................

● QQ群號: 230161599 (滿) 、618766405

● weixin群:可加我weixin,我拉大家進群,非誠勿擾

● 聯絡我請加QQ好友 646634621 ,註明新增緣由

● 於 2019-01-01 06:00 ~ 2019-01-31 24:00 在魔都完成

● 最新修改時間:2019-01-01 06:00 ~ 2019-01-31 24:00

● 文章內容來源於小麥苗的學習筆記,部分整理自網路,若有侵權或不當之處還請諒解

● 版權所有,歡迎分享本文,轉載請保留出處

........................................................................................................................

小麥苗的微店

小麥苗出版的資料庫類叢書 http://blog.itpub.net/26736162/viewspace-2142121/

小麥苗OCP、OCM、高可用網路班 http://blog.itpub.net/26736162/viewspace-2148098/

小麥苗騰訊課堂主頁 https://lhr.ke.qq.com/

........................................................................................................................

使用 weixin客戶端 掃描下面的二維碼來關注小麥苗的weixin公眾號( xiaomaimiaolhr )及QQ群(DBA寶典)、新增小麥苗weixin, 學習最實用的資料庫技術。

........................................................................................................................

歡迎與我聯絡

 

 



來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/26736162/viewspace-2564637/,如需轉載,請註明出處,否則將追究法律責任。

相關文章