本文介紹了Python中單下劃線和雙下劃線的各種含義和命名約定聂示,名稱修飾(name mangling)的工作原理,以及它如何影響Python類簇秒。
五類下劃線
1鱼喉、 前導(dǎo)單下劃線:_var
2、末尾單下劃線:var_
3趋观、前導(dǎo)雙下劃線:__var
4蒲凶、前導(dǎo)和末尾雙下劃線:__var__
5、單下劃線:_
1. 單前導(dǎo)下劃線_var
當(dāng)涉及到變量和方法名稱時拆内,單個下劃線前綴有一個約定俗成的含義色冀,它是程序員的一個提示:python社區(qū)一致認(rèn)為它應(yīng)該是什么意思痹届,但不會對程序行為產(chǎn)生影響。
告知其他程序員:以單個下劃線開頭的變量或方法僅供內(nèi)部使用(該約定在'PEP 8'中有定義)
不是python的強(qiáng)制規(guī)定。python不像JAVA那樣在"私有"和“公有”變量之間存在很強(qiáng)的區(qū)別翻斟。這就像有人用下劃線為標(biāo)識提出一個小小的警告:
“嘿玻褪,這不是真的要成為類的一個公共接口的一部分纵菌。不去管它就好”
class Test:
def __init__(self):
self.foo = 11
self._bar = 23
>>> t = Test()
>>> t.foo
11
>>> t._bar
23
_bar
中的前導(dǎo)單下劃線并未阻止我們引用它吻氧。至少相對于變量和方法名而言,前導(dǎo)單下劃線_
僅是一個定義內(nèi)部(私有)變量或方法的約定而已融欧。
但是敏弃,前導(dǎo)下劃線的確會影響從模塊中導(dǎo)入名稱的方式。
# This is my_module.py:
def external_func():
return 23
def _internal_func():
return 42
>>> from my_module import *
>>> external_func()
23
>>> _internal_func()
NameError: "name '_internal_func' is not defined"
此時噪馏,如果使用通配符從模塊中導(dǎo)入所有名稱麦到,則Python不會導(dǎo)入帶有前導(dǎo)下劃線的名稱(除非模塊定義了覆蓋此行為的all列表)。
- PEP 8推薦避免通配符導(dǎo)入欠肾,如果你遵循此約定瓶颠,那么就不必?fù)?dān)憂上述問題,只需要記状烫摇:
單個下劃線是一個Python命名約定粹淋,表示這個名稱是供內(nèi)部使用的。 它通常不由Python解釋器強(qiáng)制執(zhí)行,僅僅作為一種對程序員的提示桃移。
2屋匕、末尾單下劃線var_
- 作為一個命名用的字符,用于解決命名沖突借杰。有時候过吻,一個變量的最合適的名稱已經(jīng)被一個關(guān)鍵字所占用。 因此第步,像class或def這樣的名稱不能用作Python中的變量名稱疮装。 在這種情況下缘琅,你可以附加一個下劃線來解決命名沖突:
3粘都、前導(dǎo)雙下劃線__var
- 雙下劃線前綴會導(dǎo)致Python解釋器重寫屬性名稱,以避免子類中的命名沖突刷袍。
這也叫做名稱修飾(name mangling) —— 解釋器更改變量的名稱翩隧,以便在類被擴(kuò)展的時候不容易產(chǎn)生沖突。
class Test:
def __init__(self):
self.foo = 11
self._bar = 23
self.__baz = 23
>>> 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']
可以看見:
self.foo
變量在屬性列表中顯示為未修改為foo呻纹。
self._bar
經(jīng)解釋器解釋后并無變化堆生。
self.__baz
情況看起來有點不同,它被解釋器做了名稱修飾雷酪,變?yōu)榱?code>_Test__baz
class ExtendedTest(Test):
def __init__(self):
super().__init__()
self.foo = 'overridden'
self._bar = 'overridden'
self.__baz = 'overridden'
>>> t2 = ExtendedTest()
>>> t2.foo
'overridden'
>>> t2._bar
'overridden'
>>> t2.__baz
AttributeError: "'ExtendedTest' object has no attribute '__baz'"
直接使用__baz
引用該屬性(或方法)就出錯了淑仆。而得如下方式才能引用:
>>> t2._Test__baz
42
4、前導(dǎo)和末尾雙下劃線__var__
- 與前導(dǎo)雙下劃線
__var
不同哥力,在解釋器解釋過程中蔗怠,前導(dǎo)和末尾雙下劃線__var__
不會應(yīng)用名稱修飾。
class PrefixPostfixTest:
def __init__(self):
self.__bam__ = 42
>>> PrefixPostfixTest().__bam__
42
但是吩跋,Python保留了有雙前導(dǎo)和雙末尾下劃線的名稱寞射,用于特殊用途。 這樣的例子有锌钮,
__init__
對象構(gòu)造函數(shù)桥温,或__call__
它使得一個對象可以被調(diào)用。這些dunder方法通常被稱為神奇方法 梁丘, 但Python社區(qū)中的許多人(包括我自己)都不喜歡這種方法侵浸。
最好避免在自己的程序中使用以雙下劃線(dunders)開頭和結(jié)尾的名稱,以避免與將來Python語言的變化產(chǎn)生沖突氛谜。
5通惫、單下劃線 _
- 按照習(xí)慣,有時候單個獨立下劃線
_
用作一個名字混蔼,來表示某個變量是臨時的或無關(guān)緊要的履腋。
>>> for _ in range(32):
... print('Hello, World.')
在上述代碼段中,單下劃線_
僅作為一個臨時變量用于循環(huán)迭代。
- 在拆分(unpacking)表達(dá)式中將單個下劃線用作“不關(guān)心的”變量遵湖,以忽略特定的值悔政。
- 這個含義只是“依照約定”,并不會在Python解釋器中觸發(fā)特殊的行為延旧。 單個下劃線僅僅是一個有效的變量名稱谋国,會有這個用途而已。
>>> car = ('red', 'auto', 12, 3812.4)
>>> color, _, _, mileage = car
>>> color
'red'
>>> mileage
3812.4
>>> _
12
上述代碼段中迁沫,_
作為占位符變量使用芦瘾。
- 除了用作臨時變量之外,
_
是大多數(shù)Python REPL中的一個特殊變量集畅,它表示由解釋器評估的最近一個表達(dá)式的結(jié)果近弟。
這樣就很方便了,比如你可以在一個解釋器會話中訪問先前計算的結(jié)果挺智,或者祷愉,你是在動態(tài)構(gòu)建多個對象并與它們交互,無需事先給這些對象分配名字:
>>> 20 + 3
23
>>> _
23
>>> print(_)
23
>>> list()
[]
>>> _.append(1)
>>> _.append(2)
>>> _.append(3)
>>> _
[1, 2, 3]
改寫自:https://blog.csdn.net/tcx1992
原文作者:地球的外星人君
鏈接:https://zhuanlan.zhihu.com/p/36173202
著作權(quán)歸作者所有赦颇。商業(yè)轉(zhuǎn)載請聯(lián)系作者獲得授權(quán)二鳄,非商業(yè)轉(zhuǎn)載請注明出處。