本文介紹了Python中單下劃線和雙下劃線的5種表現形式,以及一些使用方法。其中有一些含義僅僅是依照約定,被視作是對程序員的提示,而有一些含義是由Python解釋器嚴格執行的。
- 單前導下劃線:_var
- 單末尾下劃線:var_
- 雙前導下劃線:__var
- 雙前導和末尾下劃線:__var__
- 單下劃線:_
1.單前導下劃線 _var
下劃線前綴的含義是告知其他程序員:以單個下劃線開頭的變量或方法僅供內部使用。
該約定在PEP 8中有定義。這不是Python強制規定的。而是一個約定俗成的含義。 它是對程序員的一個提示,意味著Python社區一致認為它應該是什么意思,但程序的行為不受影響。
例子:
class Test:def __init__(self):self.foo = 11self._bar = 23
實例化此類,并嘗試訪問在__init__構造函數中定義的foo和_bar屬性,會發生什么情況?
>>> t = Test()
>>> t.foo
11
>>> t._bar
23
你會看到_bar中的單個下劃線并沒有阻止我們“進入”類并訪問該變量的值。這是因為Python中的單個下劃線前綴僅僅是一個約定。
但是,如果使用通配符從模塊中導入所有名稱,則Python不會導入帶有前導下劃線的名稱。
>>> from my_module import *
>>> external_func()
23
>>> _internal_func()
NameError: "name '_internal_func' is not defined"
2. 單末尾下劃線 var_
有時候,一個變量的最合適的名稱已經被一個關鍵字所占用。 因此,像class或def這樣的名稱不能用作Python中的變量名稱。 在這種情況下,你可以附加一個下劃線來解決命名沖突:
>>> def make_object(name, class):
SyntaxError: "invalid syntax">>> def make_object(name, class_):
... pass
總之,單個末尾下劃線(后綴)是一個約定,用來避免與Python關鍵字產生命名沖突。 PEP 8解釋了這個約定。
3. 雙前導下劃線 __var
①名稱改寫
雙下劃線還可用于名稱改寫,即將屬性或方法前面的雙下劃線和類名組合起來,以防止子類意外覆蓋父類的屬性或方法。
class Test:def __init__(self):self.foo = 11self._bar = 23self.__baz = 23
讓我們用內置的dir()函數來看看這個對象的屬性:
>>> t = Test()
>>> dir(t)
['_Test__baz', '__class__', '__delattr__', '__dict__', '__dir__',
'__doc__', '__eq__', '__format__', '__ge__', '__getattribute__',
'__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__',
'__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__',
'__setattr__', '__sizeof__', '__str__', '__subclasshook__',
'__weakref__', '_bar', 'foo']
以上是這個對象屬性的列表。 讓我們來看看這個列表,并尋找我們的原始變量名稱foo,_bar和__baz ,我保證你會注意到一些有趣的變化。
self.foo變量在屬性列表中顯示為未修改為foo。
self._bar的行為方式相同 - 它以_bar的形式顯示在類上。 就像我之前說過的,在這種情況下,前導下劃線僅僅是一個約定。 給程序員一個提示而已。
然而,對于self.__baz而言,情況看起來有點不同。 當你在該列表中搜索__baz時,你會看不到有這個名字的變量。
__baz出什么情況了?
如果你仔細觀察,你會看到此對象上有一個名為_Test__baz的屬性。 這就是Python解釋器所做的名稱修飾。 它這樣做是為了防止變量在子類中被重寫。
②名稱修飾
雙下劃線用于名稱修飾,即將屬性或方法前面的雙下劃線作為前綴,使其成為私有成員。私有成員只能在類內部訪問,無法在類外部直接訪問
class ManglingTest:def __init__(self):self.__mangled = 'hello'def get_mangled(self):return self.__mangled>>> ManglingTest().get_mangled()
'hello'
>>> ManglingTest().__mangled
AttributeError: "'ManglingTest' object has no attribute '__mangled'"
4. 雙前導和雙末尾下劃線__var__
以雙下劃線開頭結尾的變量不會被python解釋器修改。
以雙下劃線開頭結尾的方法在python中稱為魔法方法。這樣的例子有,__init__對象構造函數,或__call__ ,它使得一個對象可以被調用。
為了避免與將來Python語言的變化產生沖突,我應該避免使用雙下劃線開頭和結尾的名稱。
5.單下劃線 _
按照習慣,有時候單個獨立下劃線是用作一個名字,來表示某個變量是臨時的或無關緊要的。
例如,在下面的循環中,我們不需要訪問正在運行的索引,我們可以使用“_”來表示它只是一個臨時值:
>>> for _ in range(32):
... print('Hello, World.')
你也可以在拆分(unpacking)表達式中將單個下劃線用作“不關心的”變量,以忽略特定的值。 同樣,這個含義只是“依照約定”,并不會在Python解釋器中觸發特殊的行為。 單個下劃線僅僅是一個有效的變量名稱,會有這個用途而已。
>>> car = ('red', 'auto', 12, 3812.4)
>>> color, _, _, mileage = car>>> color
'red'
>>> mileage
3812.4
>>> _
12
6.總結
模式 | 格式 | 含義 |
---|---|---|
單前導下劃線 | _var | 命名約定,僅供內部使用 |
單末尾下劃線 | var_ | 命名約定,避免與其他關鍵字命名沖突 |
雙前導雙末尾下劃線 | __var | 觸發“名稱修飾”,僅能在內部調用 |
雙前導雙末尾下劃線 | __var__ | 魔法方法 |
單下劃線 | _ | 用作臨時或者無意義的變量名稱 |