Python中的五種下划線


  1 1、單前導下划線 _var
  2 
  3 單個下划線是一個Python命名約定,表示這個名稱是供內部使用的。 它通常不由Python解釋器強制執行,僅僅作為一種對程序員的提示
  4 
  5 程序員使用名稱前的單下划線,用於指定該名稱屬性為“私有”。這有點類似於慣例,為了使其他人(或你自己)使用這些代碼時將會知道以“_”開頭的名稱只供內部使用。正如Python文檔中所述:
  6 以下划線“_”為前綴的名稱(如_spam)應該被視為API中非公開的部分(不管是函數、方法還是數據成員)。此時,應該將它們看作是一種實現細節,在修改它們時無需對外部通知。
  7 正如上面所說,這確實類似一種慣例,因為它對解釋器來說確實有一定的意義,如果你寫了代碼“from <模塊/包名> import *”,那么以“_”開頭的名稱都不會被導入,除非模塊或包中的“__all__”列表顯式地包含了它們。
  8 
  9 class Test:
 10     def __init__(self):
 11         self.foo=11
 12         self._bar=23
 13 t=Test()
 14 print(t.foo)
 15 print(t._bar)
 16 
 17 _bar中的單個下划線並沒有阻止我們“進入”類並訪問該變量的值。這是因為Python中的單個下划線前綴僅僅是一個約定 - 至少相對於變量和方法名而言。但是,前導下划線的確會影響從模塊中導入名稱的方式。
 18 假設你在一個名為client.py的模塊中有以下代碼:
 19 
 20 def external_func():
 21     return 23
 22 def _internal_func():
 23     return 42
 24 
 25 如果使用通配符從模塊中導入所有名稱,則Python不會導入帶有前導下划線的名稱(除非模塊定義了覆蓋此行為的__all__列表):
 26 from client import *
 27 print(external_func())
 28 print(_internal_func())  #NameError: name '_internal_func' is not defined
 29 順便說一下,應該避免通配符導入,因為它們使名稱空間中存在哪些名稱不清楚。 為了清楚起見,堅持常規導入更好。
 30 
 31 常規導入不受前導單個下划線命名約定的影響:
 32 import client
 33 print(client.external_func())
 34 print(client._internal_func())
 35 
 36 
 37 
 38 2、單末尾下划線 var_
 39 有時候,一個變量的最合適的名稱已經被一個關鍵字所占用。 因此,像class或def這樣的名稱不能用作Python中的變量名稱。 在這種情況下,你可以附加一個下划線來解決命名沖突:
 40 單個末尾下划線(后綴)是一個約定,用來避免與Python關鍵字產生命名沖突。 PEP 8解釋了這個約定。
 41 def make_object(name,class):
 42     pass
 43 
 44 
 45 
 46 3、雙前導下划線 __var
 47 名稱(具體為一個方法名)前雙下划線(__)的用法並不是一種慣例,對解釋器來說它有特定的意義。Python中的這種用法是為了避免與子類定義的名稱沖突。Python文檔指出,“__spam”這種形式(至少兩個前導下划線,最多一個后續下划線)的任何標識符將會被“_classname__spam”這種形式原文取代,在這里“classname”是去掉前導下划線的當前類名。
 48 
 49 class A(object):
 50     def _internal_use(self):
 51         pass
 52     def __method_name(self):
 53         pass
 54 print(dir(A()))
 55 
 56 # ['_A__method_name', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_internal_use']
 57 
 58 正如所預料的,“_internal_use”並未改變,而“__method_name”卻被變成了“_ClassName__method_name”。此時,如果你創建A的一個子類B,那么你將不能輕易地覆寫A中的方法“__method_name”。
 59 
 60 class B(A):
 61     pass
 62 print(dir(B()))
 63 
 64 # ['_A__method_name', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_internal_use']
 65 
 66 
 67 
 68 4、雙前導和雙末尾下划線 _var_
 69 也許令人驚訝的是,如果一個名字同時以雙下划線開始和結束,則不會應用名稱修飾。 由雙下划線前綴和后綴包圍的變量不會被Python解釋器修改:
 70 
 71 class PrefixPostfixTest:
 72     def __init__(self):
 73         self.__bam__=42
 74 print(PrefixPostfixTest().__bam__) # 42
 75 
 76 但是,Python保留了有雙前導和雙末尾下划線的名稱,用於特殊用途。 這樣的例子有,__init__對象構造函數,或__call__ --- 它使得一個對象可以被調用。
 77 這些dunder方法通常被稱為神奇方法 - 但Python社區中的許多人都不喜歡這種方法。
 78 最好避免在自己的程序中使用以雙下划線(“dunders”)開頭和結尾的名稱,以避免與將來Python語言的變化產生沖突。
 79 
 80 
 81 
 82 
 83 1、在解釋器中:在這種情況下,“_”代表交互式解釋器會話中上一條執行的語句的結果。這種用法首先被標准CPython解釋器采用,然后其他類型的解釋器也先后采用。
 84  2、作為一個名稱:這與上面一點稍微有些聯系,此時“_”作為臨時性的名稱使用。這樣,當其他人閱讀你的代碼時將會知道,你分配了一個特定的名稱,但是並不會在后面再次用到該名稱。例如,下面的例子中,你可能對循環計數中的實際值並不感興趣,此時就可以使用“_”。
 85 n = 42
 86 for _ in range(n):
 87 do_something()
 88 3、國際化:也許你也曾看到”_“會被作為一個函數來使用。這種情況下,它通常用於實現國際化和本地化字符串之間翻譯查找的函數名稱,這似乎源自並遵循相應的C約定。
 89 
 90 可以發現,場景二和場景三中的使用方法可能會相互沖突,所以我們需要避免在使用“_”作為國際化查找轉換功能的代碼塊中同時使用“_”作為臨時名稱。
 91 
 92 總結:
 93 Python下划線命名模式 - 小結
 94 以下是一個簡短的小結,即“速查表”,羅列了本文中談到的五種Python下划線模式的含義:
 95 
 96 
 97 
 98 轉載自:《不知道這5種下划線的含義,你就不算真的會Python!》
 99 subtitle
100 51Testing軟件測試網
101 03-07 17:35

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM