1. 程式人生 > >不知道這5種下劃線的含義,你就不算真的會Python!

不知道這5種下劃線的含義,你就不算真的會Python!

什麼是 Python? Python 之父 Guido van Rossum 說:Python是一種高階程式語言,其核心設計哲學是程式碼可讀性和語法,能夠讓程式設計師用很少的程式碼來表達自己的想法。

對於我來說,學習 Python 的首要原因是,Python 是一種可以優雅程式設計的語言。它能夠簡單自然地寫出程式碼和實現我的想法。

另一個原因是我們可以將 Python 用在很多地方:人工智慧、資料科學、Web 開發和機器學習等都可以使用 Python 來開發。

國慶期間後臺有小夥伴留言問我:“Python變數和方法名稱中單下劃線和雙下劃線的含義是什麼?”我想一些初學者或者經驗尚淺的朋友一定也會有這個疑問,所以今天我就來跟大家聊聊Python中這個很重要的“下劃線”!

單下劃線和雙下劃線在Python變數和方法名稱中都各有其含義。有一些含義僅僅是依照約定,被視作是對程式設計師的提示 - 而有一些含義是由Python直譯器嚴格執行的。

那麼,下面就為大家介紹一下Python中單下劃線和雙下劃線("dunder")的各種含義和命名約定,名稱修飾(name mangling)的工作原理,以及它如何影響你自己的Python類。

下面將討論以下五種下劃線模式和命名約定,以及它們如何影響Python程式的行為:

單前導下劃線:_var

單末尾下劃線:var_

雙前導下劃線:__var

雙前導和末尾下劃線:__var__

單下劃線:_

1、單前導下劃線 _var

程式設計師使用名稱前的單下劃線,用於指定該名稱屬性為“私有”。這有點類似於慣例,為了使其他人(或你自己)使用這些程式碼時將會知道以“_”開頭的名稱只供內部使用。正如Python文件中所述:

以下劃線“_”為字首的名稱(如_spam)應該被視為API中非公開的部分(不管是函式、方法還是資料成員)。此時,應該將它們看作是一種實現細節,在修改它們時無需對外部通知。

正如上面所說,這確實類似一種慣例,因為它對直譯器來說確實有一定的意義,如果你寫了程式碼“from <模組/包名> import *”,那麼以“_”開頭的名稱都不會被匯入,除非模組或包中的“__all__”列表顯式地包含了它們。

看看下面的例子:

class Test: def __init__(self): self.foo = 11 self._bar = 23

如果你例項化此類,並嘗試訪問在__init__建構函式中定義的foo和_bar屬性,會發生什麼情況? 讓我們來看看:

>>> t = Test() >>> t.foo 11 >>> t._bar 23

你會看到_bar中的單個下劃線並沒有阻止我們“進入”類並訪問該變數的值。

這是因為Python中的單個下劃線字首僅僅是一個約定 - 至少相對於變數和方法名而言。

但是,前導下劃線的確會影響從模組中匯入名稱的方式。

假設你在一個名為my_module的模組中有以下程式碼:

# This is my_module.py: def external_func(): return 23 def _internal_func(): return 42

現在,如果使用萬用字元從模組中匯入所有名稱,則Python不會匯入帶有前導下劃線的名稱(除非模組定義了覆蓋此行為的__all__列表):

>>> from my_module import * >>> external_func() 23 >>> _internal_func() NameError: "name '_internal_func' is not defined"

順便說一下,應該避免萬用字元匯入,因為它們使名稱空間中存在哪些名稱不清楚。 為了清楚起見,堅持常規匯入更好。

與萬用字元匯入不同,常規匯入不受前導單個下劃線命名約定的影響:

>>> import my_module >>> my_module.external_func() 23 >>> my_module._internal_func() 42

我們知道這一點可能有點令人困惑。 如果你遵循PEP 8推薦,避免萬用字元匯入,那麼你真正需要記住的只有這個:

單個下劃線是一個Python命名約定,表示這個名稱是供內部使用的。 它通常不由Python直譯器強制執行,僅僅作為一種對程式設計師的提示。

2、單末尾下劃線 var_

有時候,一個變數的最合適的名稱已經被一個關鍵字所佔用。 因此,像class或def這樣的名稱不能用作Python中的變數名稱。 在這種情況下,你可以附加一個下劃線來解決命名衝突:

>>> def make_object(name, class): SyntaxError: "invalid syntax" >>> def make_object(name, class_): ... pass

總之,單個末尾下劃線(字尾)是一個約定,用來避免與Python關鍵字產生命名衝突。 PEP 8解釋了這個約定。

3、雙前導下劃線 __var

名稱(具體為一個方法名)前雙下劃線(__)的用法並不是一種慣例,對直譯器來說它有特定的意義。Python中的這種用法是為了避免與子類定義的名稱衝突。Python文件指出,“__spam”這種形式(至少兩個前導下劃線,最多一個後續下劃線)的任何識別符號將會被“_classname__spam”這種形式原文取代,在這裡“classname”是去掉前導下劃線的當前類名。

例如下面的例子:

>>> class A(object):

... def _internal_use(self):

... pass

... def __method_name(self):

... pass

...

>>> dir(A())

['_A__method_name', ..., '_internal_use']

正如所預料的,“_internal_use”並未改變,而“__method_name”卻被變成了“_ClassName__method_name”。此時,如果你建立A的一個子類B,那麼你將不能輕易地覆寫A中的方法“__method_name”。

>>> class B(A):

... def __method_name(self):

... pass

...

>>> dir(B())

['_A__method_name', '_B__method_name', ..., '_internal_use']

這裡的功能幾乎和Java中的final方法和C++類中標準方法(非虛方法)一樣。

4、雙前導和雙末尾下劃線 _var_

也許令人驚訝的是,如果一個名字同時以雙下劃線開始和結束,則不會應用名稱修飾。 由雙下劃線字首和字尾包圍的變數不會被Python直譯器修改:

class PrefixPostfixTest: def __init__(self): self.__bam__ = 42 >>> PrefixPostfixTest().__bam__ 42

但是,Python保留了有雙前導和雙末尾下劃線的名稱,用於特殊用途。 這樣的例子有,__init__物件建構函式,或__call__ --- 它使得一個物件可以被呼叫。

這些dunder方法通常被稱為神奇方法 - 但Python社群中的許多人都不喜歡這種方法。

最好避免在自己的程式中使用以雙下劃線(“dunders”)開頭和結尾的名稱,以避免與將來Python語言的變化產生衝突。

5、單下劃線 _

通常情況下,會在以下3種場景中使用:

1、在直譯器中:在這種情況下,“_”代表互動式直譯器會話中上一條執行的語句的結果。這種用法首先被標準CPython直譯器採用,然後其他型別的直譯器也先後採用。

>>> _ Traceback (most recent call last):

File "<stdin>", line 1, in <module>

NameError: name '_' is not defined

>>> 42

>>> _

42

>>> 'alright!' if _ else ':('

'alright!'

>>> _

'alright!'

2、作為一個名稱:這與上面一點稍微有些聯絡,此時“_”作為臨時性的名稱使用。這樣,當其他人閱讀你的程式碼時將會知道,你分配了一個特定的名稱,但是並不會在後面再次用到該名稱。例如,下面的例子中,你可能對迴圈計數中的實際值並不感興趣,此時就可以使用“_”。

n = 42

for _ in range(n):

do_something()

3、國際化:也許你也曾看到”_“會被作為一個函式來使用。這種情況下,它通常用於實現國際化和本地化字串之間翻譯查詢的函式名稱,這似乎源自並遵循相應的C約定。

例如,在Django文件“轉換”章節中,你將能看到如下程式碼:

from django.utils.translation import ugettext as _

from django.http import HttpResponse

def my_view(request):

output = _("Welcome to my site.")

return HttpResponse(output)

可以發現,場景二和場景三中的使用方法可能會相互衝突,所以我們需要避免在使用“_”作為國際化查詢轉換功能的程式碼塊中同時使用“_”作為臨時名稱。

總結:

Python下劃線命名模式 - 小結

以下是一個簡短的小結,即“速查表”,羅列了本文中談到的五種Python下劃線模式的含義:

​歡迎加入  51軟體測試大家庭,在這裡你將獲得【最新行業資訊】,【免費測試工具安裝包】,【軟體測試技術乾貨】,【面試求職技巧】... 51與你共同學習,一起成長!期待你的加入: QQ              群:             755431660