Python 中的單下劃線和雙下劃線

鹹魚Linux運維發表於2023-11-29

哈嘍大家好,我是鹹魚

當我們在學習 Python 的時候,可能會經常遇到單下劃線 _ 和雙下劃線 __ 這兩種命名方式

單下劃線 _ 和雙下劃線 __ 不僅僅是隻是一種簡單的命名習慣,它們在 Python 中有著特殊的含義,對於程式碼的可讀性和功能實現有著關鍵的作用。

那麼今天我們來看一看在 Python 中單下劃線和雙下劃線的用法和意義

前導單下劃線

前導單下劃線(Leading Single Underscore)通常用於命名變數、方法和屬性,表示這些命名的元素是【私有】的或者說是【內部使用】的。

這種命名約定並不是嚴格的語言規則(即非強制性),而是一種約定,告訴開發人員該物件不應該被外部直接訪問或修改

_internal_variable = 10

比如說下面的例子中,_internal_var_internal_method都以前導單下劃線開頭,表示它們是類的內部使用。

public_method是公共方法,可以在類外部訪問。

class MyClass:
    def __init__(self):
        self._internal_var = 42  # 前導單下劃線表示該變數是內部使用的

    def _internal_method(self):
        return 'This is an internal method'

    def public_method(self):
        # 在公共方法中呼叫內部方法和變數
        print(self._internal_method())
        print(f'The internal variable is: {self._internal_var}')

雖然可以在類外部訪問前導單下劃線命名的變數和方法,但是按照約定,建議只在類內部使用,而避免在類外部直接訪問它們。

單下劃線

單下劃線通常用作一個佔位符,用於表示一個不重要的變數名或迭代中的臨時變數,即在解構賦值或迴圈迭代中不需要使用的變數

例子一中,_ 用作一個佔位符變數,表示在tuple_returning_function()返回的元組中的某個值,但是在解構賦值中沒有被使用。

def tuple_returning_function():
    return (1,1), (2,2), (3,3)

_ , tuple_I_need, _ = tuple_returning_function()

例子二中,_ 用作迴圈迭代中的佔位符,因為迴圈體中不需要使用迴圈變數的值,只是執行了三次列印操作

for _ in range(0,3):
  print("列印三次")

單尾隨下劃線

單個字尾下劃線(Single trailing underscores)通常用於避免與 Python 關鍵字產生命名衝突。它被用作識別符號的字尾,以示與Python關鍵字有所區別。

比如說我想使用一個在 Python 中已經是保留關鍵字的變數名時,比如class、def、type等。為了避免衝突,可以新增字尾下劃線

class_ = "Computer Science"
type_ = “字串”

Dunder 方法

Dunder 方法指的是以雙下劃線(__)開頭和結尾的特殊方法(也稱為魔術方法或特殊方法)。

這些方法具有特殊的行為,可以在自定義類中重寫以改變類的行為。Dunder方法的名稱是Python中預定義的,例如__init____str____repr__等。

下面是一些常見的 Dunder 方法:

  1. __init__(self, ...): 初始化方法,在物件例項化時呼叫,用於初始化物件的屬性。
  2. __str__(self): 將物件轉換為字串表示形式,當使用print()函式或str()函式時呼叫。
  3. __repr__(self): 返回一個包含物件資訊的字串,通常用於開發和除錯,可透過repr()函式呼叫。
  4. __len__(self): 返回物件的長度,透過len()函式呼叫。
  5. __getitem__(self, key): 獲取物件的元素,用於索引操作,例如obj[key]
  6. __setitem__(self, key, value): 設定物件的元素,用於索引賦值操作,例如obj[key] = value
  7. __delitem__(self, key): 刪除物件的元素,用於索引刪除操作,例如del obj[key]
  8. __call__(self, ...): 將物件作為函式呼叫,使得物件例項可呼叫。

我們在下面的例子中定義了 __add__ dunder 方法,並建立了兩個例項

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __add__(self, other):
        return Point(self.x + other.x, self.y + other.y)

    def __str__(self):
        return f"({self.x}, {self.y})"
p1 = Point(1, 2)
p2 = Point(3, 4)
p3 = p1 + p2
print(p3)  # Output: (4, 6)

我們定義了一個 Point 類,它有 xy 兩個例項變數以及__add__ 方法和__str__ 方法

當我們使用 + 運算子對 Point 的兩個例項(p1、p2)求和時,__add__ 會自動呼叫。它返回一個新 的 Point 物件(p3),其 xy 值是兩個原始 Point物件的 xy 值的和

當使用print()函式時呼叫自定義的__str__ 方法

前導雙下劃線

前導雙下劃線作為字首在物件名前使用時,表示這是一個特殊的命名約定,它在類定義中用於建立私有屬性或方法。

當在類中使用雙下劃線作為字首時,Python 直譯器會自動修改屬性名,以避免在子類中發生命名衝突。這個過程被稱為名稱修飾(name mangling)

比如下面這個例子:

class MyClass:
    def __init__(self):
        self.__private_var = 10

    def get_private_var(self):
        return self.__private_var

# 建立類的例項
obj = MyClass()

# 嘗試訪問私有屬性
print(obj.__private_var)  # 會丟擲 AttributeError 錯誤,因為這個屬性名稱已被修改

# 透過呼叫訪問私有屬性的方法來獲取
print(obj.get_private_var())  # 輸出: 10

__private_var屬性在類內部被訪問,但是在類外部直接訪問會導致 AttributeError 錯誤。

這是因為 Python 對 __private_var 進行了名稱修飾,實際名稱變成了 obj._MyClass__private_var,這樣避免了外部直接訪問

但是我們可以透過呼叫類內部方法 get_private_var() 在類外部訪問私有屬性。

透過使用前導雙下劃線,以確保類的某些屬性或方法只能從類本身內部訪問。這有助於防止意外修改重要的內部資料,並使程式碼更加可靠和可維護

但如果你知道修飾後的名稱,你仍可以在類外部去訪問

相關文章