Python中的下劃線

Python中的下劃線


018.11.25

前言

我發現公司裏即便是工作經驗一年的程序員依然對Python的私有屬性有些迷糊——也就是下劃線的問題——拿捏不準要怎麼用。我想在此總結一下。

單下劃線

前置

前置單下劃線是一種約定,即:認爲這個變量或方法是類私有,外界不要調用。在這裏,對象認爲是“外界”。

示例如下:

class Persion(object):
    def __init__(self, name, age, hobbies):
        # 不建議被外界使用
        self._name = name
        self._age = age
        self._hobbies = hobbies

    # 允許被外界調用
    @property
    def detail(self):
        return self._get_sentence()

    # 建議不要被外界調用,而是在類中使用
    def _get_sentence(self):
        return f"{self._name} is {self._age} and loves {self._hobbies}."


if __name__ == "__main__":
    lily = Persion("lily", 18, "listenning")
    print(lily.detail)

# 輸出:
# lily is 18 and loves listenning.

但外界能不能調用帶前置單下劃線的成員變量和成員方法呢?事實上是可以的:

print(lily._name)  # 輸出:lily
print(lily._get_sentence())  # 輸出: lily is 18 and loves listening.

我實在記不清是《Python編程之美》還是《數據結構(Python描述)》,裏面對此解釋說:之所以Python對類私有隻是一種約定,是認爲使用Python開發的程序員應該是成熟的。


而另一方面,在一個模塊中,前置單下劃線的變量或是函數,不能通過from module import *方式導入。如:

# demo1.py

# 這是一個變量
_one = "ONE"

# 這是一個函數
def _two():
    print("TWO")
# demo2.py
from demo1 import *

print(_one)  # 錯誤使用
_two()  # 錯誤使用

對此解釋器會拋出異常:NameError: name 'xxx' is not defined

但並非demo1中的前置單下劃線變量/方法在demo2中就不可以使用,完全可以import module,然後通過module.xxx方式,demo2代碼做如下調整:

# demo2.py
import demo1

print(demo1._one)  # 正確使用
demo1._two()  # 正確使用

後置

後置單下劃線是一種編程風格建議,即:當你的變量/方法名與Python中的關鍵字衝突時,可以加上後置單下劃線做區分。如:

list_ = ["lily", "bob", "green"]
dict_ = {
    "name": "lily",
    "age": 18
}

雙下劃線

前置

事實上,前置雙下劃線變量/方法,更像是類私有。將第一個示例代碼改寫如下(單下劃線都改寫爲雙下劃線):

class Persion(object):
    def __init__(self, name, age, hobbies):
        # 不能被外界訪問
        self.__name = name
        self.__age = age
        self.__hobbies = hobbies

    # 允許被外界調用
    @property
    def detail(self):
        return self.__get_sentence()
	
	# 不能被外界調用
    def __get_sentence(self):
        return f"{self.__name} is {self.__age} and loves {self.__hobbies}."


if __name__ == "__main__":
    lily = Persion("lily", 18, "listening")
    print(lily.detail)

# 輸出:
# lily is 18 and loves listening.

可如果你想外界訪問:

print(lily.__name)  # 錯誤示例
print(lily.__get_sentence())  # 錯誤示例

解釋器會拋異常:AttributeError: 'Persion' object has no attribute '__name'

其實同前置單下劃線一樣,雙下劃線其實也可以被外界訪問,只不過解釋器對他們**“以類之姓,冠它之名”**。

print(lily._Persion__name)  # 輸出:lily
lily._Persion__get_sentence()  # 輸出:lily is 18 and loves listening.

也就是說,當類名爲X,雙下劃線變量爲__y時,外界對其訪問應該形如:_X__y


完全與前置單下劃線一樣的是,模塊中的前置雙下劃線變量/函數,不能通過from module import *導入,但可以import module後使用:

module.__one
module.__two()

前置雙下劃線存在的意義:爲了避免該成員的名稱與子類中的名稱衝突

後置

開個玩笑。

後置雙下劃線既沒有實際意義,也不是編程風格的建議。

前後置

稍微對Python熟悉的人就會知道,存在前置雙下劃線同時還有後置雙下劃線的變量以及方法。如常見的__name__以及__init__()。這些屬於Python的魔法對象,是爲了區別其他用戶自定義的命名。官方表示:永遠不要將這樣的命名方式應用於自己的變量或函數

感謝

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章