最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Python開發(fā)中“雙下劃線私有成員的名稱修飾”問(wèn)題解決辦法

 更新時(shí)間:2026年05月08日 08:29:10   作者:深山技術(shù)宅  
Python是一種簡(jiǎn)單、易學(xué)、功能強(qiáng)大的編程語(yǔ)言,被廣泛應(yīng)用于各種領(lǐng)域,在Python中下劃線的使用有其特殊的含義和用途,這篇文章主要介紹了Python開發(fā)中“雙下劃線私有成員的名稱修飾”問(wèn)題的解決辦法,需要的朋友可以參考下

前言

在 Python 面向?qū)ο缶幊讨?,雙下劃線(__)前綴的屬性或方法常被稱為“私有成員”。但與其他語(yǔ)言(如 Java 的 private)不同,Python 并沒有真正的訪問(wèn)控制——雙下劃線前綴觸發(fā)的是一種被稱為**名稱修飾(Name Mangling)**的編譯期重命名機(jī)制。許多開發(fā)者誤以為它能提供絕對(duì)的安全性,結(jié)果在實(shí)際使用中遭遇無(wú)法訪問(wèn)、繼承失效、測(cè)試?yán)щy等問(wèn)題。

本文將深入剖析名稱修飾的底層原理、設(shè)計(jì)初衷、常見陷阱,并給出清晰的使用指南和替代方案。

一、現(xiàn)象復(fù)現(xiàn):雙下劃線成員的“隱身術(shù)”

基礎(chǔ)示例

class Parent:
    def __init__(self):
        self.__secret = 42   # 雙下劃線屬性

    def reveal(self):
        return self.__secret

p = Parent()
print(p.reveal())        # 42 (內(nèi)部訪問(wèn)正常)
print(p.__secret)        # AttributeError: 'Parent' object has no attribute '__secret'

外部直接訪問(wèn) p.__secret 失敗,似乎實(shí)現(xiàn)了“私有”。但真相是:

print(p._Parent__secret)   # 42  ← 只是換了個(gè)名字!

繼承中的意外遮蔽

class Child(Parent):
    def __init__(self):
        super().__init__()
        self.__secret = 100   # 本意是覆蓋父類的 __secret

c = Child()
print(c.reveal())          # 42  ← 為什么不是 100?
print(c._Parent__secret)   # 42
print(c._Child__secret)    # 100

子類定義的 __secret 并未覆蓋父類的同名屬性,而是創(chuàng)建了一個(gè)獨(dú)立的新屬性

二、名稱修飾的原理

1. 修飾規(guī)則

當(dāng) Python 編譯器在類定義體內(nèi)遇到以至少兩個(gè)下劃線開頭、最多一個(gè)下劃線結(jié)尾的標(biāo)識(shí)符時(shí),會(huì)將其自動(dòng)重命名為:

_ClassName__identifier
  • ClassName當(dāng)前類名(定義該標(biāo)識(shí)符的類)。
  • 若標(biāo)識(shí)符僅以雙下劃線結(jié)尾(如 __init__、__call__),則不進(jìn)行修飾。
  • 修飾過(guò)程發(fā)生在編譯時(shí),與運(yùn)行時(shí)無(wú)關(guān)。

2. 驗(yàn)證編譯結(jié)果

class MyClass:
    __value = 1

print(MyClass.__dict__)
# {'_MyClass__value': 1, ...}

可見類的 __dict__ 中實(shí)際存儲(chǔ)的是修飾后的名稱。

3. 修飾的觸發(fā)范圍

名稱修飾僅對(duì)在類定義體內(nèi)直接出現(xiàn)的標(biāo)識(shí)符有效。通過(guò)字符串賦值(如 setattr)或直接在 __dict__ 中插入的鍵不會(huì)被修飾。

class Test:
    def __init__(self):
        self.__attr = 10           # 修飾為 _Test__attr
        setattr(self, '__attr2', 20) # 不修飾,保持 '__attr2'

t = Test()
print(t._Test__attr)   # 10
print(t.__attr2)       # 20 (可正常訪問(wèn))

三、設(shè)計(jì)初衷:避免命名沖突,而非強(qiáng)制私有

名稱修飾的目的不是實(shí)現(xiàn)類似 Java 的 private 訪問(wèn)控制,而是:

在繼承體系中,防止子類無(wú)意中覆蓋父類的“私有”屬性。

典型場(chǎng)景:框架或大型類庫(kù)

假設(shè)你開發(fā)了一個(gè)可繼承的基類,內(nèi)部使用了一個(gè)臨時(shí)變量名 __cache。你希望子類可以自由定義自己的 __cache 而不會(huì)破壞基類的內(nèi)部邏輯。名稱修飾恰好提供了這種隔離。

class FrameworkBase:
    def __init__(self):
        self.__cache = {}

    def operation(self):
        self.__cache['key'] = 'value'   # 始終操作基類的 __cache

class UserSubclass(FrameworkBase):
    def __init__(self):
        super().__init__()
        self.__cache = []   # 無(wú)意或有意使用同名屬性,不會(huì)影響基類

obj = UserSubclass()
obj.operation()   # 基類邏輯正常工作

若沒有名稱修飾,UserSubclass__cache 會(huì)覆蓋基類的 self.__cache,導(dǎo)致基類的 operation 方法操作了錯(cuò)誤的列表,引發(fā)類型錯(cuò)誤或邏輯混亂。

四、常見陷阱與反模式

陷阱 1:誤以為它是真正的私有/安全機(jī)制

class BankAccount:
    def __init__(self, balance):
        self.__balance = balance

account = BankAccount(1000)
# 攻擊者只需知道修飾規(guī)則即可繞過(guò)
account._BankAccount__balance = 0

結(jié)論: 名稱修飾不能用來(lái)保護(hù)敏感數(shù)據(jù)或作為安全邊界。任何有權(quán)訪問(wèn)對(duì)象的人都可以通過(guò)修飾后的名稱讀寫屬性。

陷阱 2:在子類中試圖覆蓋雙下劃線方法

class Base:
    def __method(self):
        return "Base"

    def call(self):
        return self.__method()

class Derived(Base):
    def __method(self):
        return "Derived"

d = Derived()
print(d.call())   # 輸出 "Base",而非 "Derived"

由于名稱修飾,Base.__method 變成 _Base__method,而 Derived.__method 變成 _Derived__method?;惖?call 方法始終調(diào)用 _Base__method,無(wú)法被子類覆蓋。

若需要子類重寫,應(yīng)使用單下劃線(_method)表示“受保護(hù)”的約定。

陷阱 3:與動(dòng)態(tài)特性沖突

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

obj = MyClass()
print(getattr(obj, '__value'))   # AttributeError
print(getattr(obj, '_MyClass__value'))   # 10

在使用 hasattr、getattrsetattr 等動(dòng)態(tài)函數(shù)時(shí),必須手動(dòng)構(gòu)造修飾后的名稱,增加了不必要的復(fù)雜性。

陷阱 4:在元類或裝飾器中使用

def add_property(cls):
    cls.__secret = 42   # 修飾為 _add_property__secret ?不,這里是全局作用域
    return cls

@add_property
class MyClass:
    pass

print(MyClass.__secret)   # 42  ← 竟然沒被修飾!

名稱修飾僅在類定義體內(nèi)部觸發(fā)。在類外部的函數(shù)或裝飾器中賦值,雙下劃線前綴不會(huì)被修飾,因?yàn)樗辉陬惖脑~法作用域內(nèi)。

陷阱 5:?jiǎn)卧獪y(cè)試和調(diào)試的額外負(fù)擔(dān)

class Service:
    def __init__(self):
        self.__clients = []

# 測(cè)試代碼
def test_service():
    s = Service()
    s._Service__clients.append('mock')   # 丑陋且脆弱

一旦類名重構(gòu),所有測(cè)試中的修飾名都需同步修改。

五、單下劃線 vs 雙下劃線:選擇指南

前綴行為語(yǔ)義約定適用場(chǎng)景
_name無(wú)名稱修飾“受保護(hù)的”內(nèi)部實(shí)現(xiàn),不應(yīng)在外部使用(但 Python 不強(qiáng)制)供子類繼承或重寫的內(nèi)部方法/屬性
__name名稱修飾避免子類命名沖突,強(qiáng)制隔離基類內(nèi)部真正不希望被子類意外覆蓋的成員
__name__無(wú)修飾(系統(tǒng)保留)特殊方法(魔法方法),由 Python 語(yǔ)言定義操作符重載、協(xié)議實(shí)現(xiàn)

最佳實(shí)踐:

  • 絕大多數(shù)情況使用單下劃線 _ 表示“請(qǐng)勿直接訪問(wèn)”。
  • 僅在大型框架或確實(shí)需要防止子類無(wú)意覆蓋時(shí)使用雙下劃線 __。
  • 永遠(yuǎn)不要使用雙下劃線來(lái)“隱藏”敏感數(shù)據(jù)。

六、如何正確使用雙下劃線成員?

1. 內(nèi)部訪問(wèn)時(shí)保持一致

在類內(nèi)部,直接使用原始的 __name 即可,編譯器會(huì)自動(dòng)修飾。

class MyClass:
    def __init__(self):
        self.__data = []

    def add(self, item):
        self.__data.append(item)   # 自動(dòng)修飾為 _MyClass__data

2. 外部訪問(wèn)時(shí)明確意圖

如果你確實(shí)需要從外部訪問(wèn)(如調(diào)試、測(cè)試),顯式使用修飾后的名稱,并注釋說(shuō)明:

obj._MyClass__data   # 訪問(wèn)前應(yīng)三思,并做好類名變更的準(zhǔn)備

3. 避免在子類中定義同名雙下劃線成員

除非你明確想要一個(gè)完全獨(dú)立于父類的屬性(不覆蓋),否則應(yīng)使用單下劃線版本。

4. 文檔化你的“私有”成員

無(wú)論是單下劃線還是雙下劃線,都應(yīng)在文檔字符串中說(shuō)明其用途和穩(wěn)定性承諾。

七、替代方案:更優(yōu)雅的“私有”實(shí)現(xiàn)

1. 使用@property控制訪問(wèn)

class Thermometer:
    def __init__(self):
        self._celsius = 0

    @property
    def celsius(self):
        return self._celsius

    @celsius.setter
    def celsius(self, value):
        if value < -273.15:
            raise ValueError("Below absolute zero")
        self._celsius = value

2. 使用閉包隱藏狀態(tài)(不依賴名稱修飾)

def create_counter():
    count = 0
    def inc():
        nonlocal count
        count += 1
        return count
    return inc

3. 使用模塊級(jí)私有約定

在模塊中,以單下劃線開頭的名稱不會(huì)被 from module import * 導(dǎo)入(除非定義了 __all__)。

八、調(diào)試與檢查技巧

1. 查看類的真實(shí)屬性

print(dir(obj))   # 列出所有屬性,包括修飾后的名稱

2. 在源碼中識(shí)別名稱修飾

現(xiàn)代 IDE(PyCharm、VS Code)會(huì)識(shí)別雙下劃線成員,并在自動(dòng)補(bǔ)全時(shí)提示修飾后的名稱。

3. 使用inspect獲取源碼

import inspect
print(inspect.getsource(MyClass))   # 查看原始定義,未被修飾

4. 靜態(tài)檢查工具

  • pylint 提供 W0238: Attribute name __xxx__ is a special method 等警告。
  • flake8 插件可檢測(cè)到可疑的雙下劃線用法。

九、總結(jié)對(duì)比表

特性雙下劃線 __name單下劃線 _name
名稱修飾? 是? 否
防止外部訪問(wèn)? 不能真正阻止,只是改名? 純約定
防止子類覆蓋? 是主要目的? 子類可自由覆蓋
訪問(wèn)復(fù)雜度需構(gòu)造修飾名直接訪問(wèn)
適用場(chǎng)景框架基類內(nèi)部隔離絕大多數(shù)內(nèi)部實(shí)現(xiàn)
Python 社區(qū)推薦度???????

十、結(jié)語(yǔ)

雙下劃線名稱修飾是 Python 提供的一個(gè)精巧的工具,用于解決特定場(chǎng)景下的命名沖突問(wèn)題。然而,將其誤解為“強(qiáng)制私有”或“安全邊界”是危險(xiǎn)的。記住核心原則:

  • 名稱修飾 != 訪問(wèn)控制
  • 單下劃線是約定,雙下劃線是隔離
  • 僅在確實(shí)需要防止子類無(wú)意覆蓋時(shí)才使用雙下劃線

遵循這些原則,你既能享受名稱修飾帶來(lái)的繼承安全性,又能避免不必要的代碼復(fù)雜性和維護(hù)負(fù)擔(dān)。在絕大多數(shù)日常開發(fā)中,良好的命名約定和團(tuán)隊(duì)規(guī)范遠(yuǎn)比語(yǔ)言層面的“花招”更為可靠。

到此這篇關(guān)于Python開發(fā)中“雙下劃線私有成員的名稱修飾”問(wèn)題解決辦法的文章就介紹到這了,更多相關(guān)Python雙下劃線私有成員的名稱修飾內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Flask 入門Web 微框架Hello Flask

    Flask 入門Web 微框架Hello Flask

    這篇文章主要介紹了 Flask 入門Web 微框架Hello Flask,F(xiàn)lask 是一個(gè) Python 實(shí)現(xiàn)的 Web 微框架,之所以稱之為微框架,是因?yàn)?nbsp;Flask 核心簡(jiǎn)單且易于擴(kuò)展,有兩個(gè)主要依賴,WSGI工具集:Werkzeug和模板引擎:Jinja2,Flask 只保留了 Web 開發(fā)的核心功能,需要的朋友可以參考一下
    2021-11-11
  • pytorch  網(wǎng)絡(luò)參數(shù) weight bias 初始化詳解

    pytorch 網(wǎng)絡(luò)參數(shù) weight bias 初始化詳解

    這篇文章主要介紹了pytorch 網(wǎng)絡(luò)參數(shù) weight bias 初始化詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-06-06
  • python使用phoenixdb操作hbase的方法示例

    python使用phoenixdb操作hbase的方法示例

    這篇文章主要介紹了python使用phoenixdb操作hbase的方法示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-02-02
  • pandas中數(shù)據(jù)的排序與排名的具體使用

    pandas中數(shù)據(jù)的排序與排名的具體使用

    Pandas對(duì)數(shù)據(jù)進(jìn)行排序和排名是非常常見的操作,本文主要介紹了pandas中數(shù)據(jù)的排序與排名的具體使用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2024-07-07
  • PyTorch實(shí)現(xiàn)MNIST數(shù)據(jù)集手寫數(shù)字識(shí)別詳情

    PyTorch實(shí)現(xiàn)MNIST數(shù)據(jù)集手寫數(shù)字識(shí)別詳情

    這篇文章主要介紹了PyTorch實(shí)現(xiàn)MNIST數(shù)據(jù)集手寫數(shù)字識(shí)別詳情,文章圍繞主題展開詳細(xì)的內(nèi)容戒殺,具有一定的參考價(jià)值,需要的朋友可以參考一下
    2022-09-09
  • Python實(shí)現(xiàn)PS圖像調(diào)整黑白效果示例

    Python實(shí)現(xiàn)PS圖像調(diào)整黑白效果示例

    這篇文章主要介紹了Python實(shí)現(xiàn)PS圖像調(diào)整黑白效果,結(jié)合實(shí)例形式分析了Python實(shí)現(xiàn)PS圖像的黑白效果原理與相關(guān)操作技巧,需要的朋友可以參考下
    2018-01-01
  • python rsa 加密解密

    python rsa 加密解密

    本篇文章主要介紹了python rsa加密解密 (編解碼,base64編解碼)的相關(guān)知識(shí)。具有很好的參考價(jià)值,下面跟著小編一起來(lái)看下吧
    2017-03-03
  • 對(duì)Pycharm創(chuàng)建py文件時(shí)自定義頭部模板的方法詳解

    對(duì)Pycharm創(chuàng)建py文件時(shí)自定義頭部模板的方法詳解

    今天小編就為大家分享一篇對(duì)Pycharm創(chuàng)建py文件時(shí)自定義頭部模板的方法詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2019-02-02
  • python3+PyQt5重新實(shí)現(xiàn)自定義數(shù)據(jù)拖放處理

    python3+PyQt5重新實(shí)現(xiàn)自定義數(shù)據(jù)拖放處理

    這篇文章主要為大家詳細(xì)介紹了python3+PyQt5重新實(shí)現(xiàn)自定義數(shù)據(jù)拖放處理,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-04-04
  • 解決pycharm下os.system執(zhí)行命令返回有中文亂碼的問(wèn)題

    解決pycharm下os.system執(zhí)行命令返回有中文亂碼的問(wèn)題

    今天小編就為大家分享一篇解決pycharm下os.system執(zhí)行命令返回有中文亂碼的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2019-07-07

最新評(píng)論

新巴尔虎右旗| 洛扎县| 专栏| 商水县| 和平区| 开江县| 泾源县| 五原县| 奉贤区| 贵溪市| 芜湖市| 枣强县| 深圳市| 托里县| 云阳县| 普安县| 南和县| 古蔺县| 徐州市| 麻栗坡县| 禄丰县| 驻马店市| 北安市| 昆明市| 长泰县| 隆子县| 黎城县| 夏津县| 阳山县| 城固县| 都匀市| 叶城县| 西青区| 长宁区| 东丰县| 山阴县| 甘德县| 株洲县| 丰城市| 阿荣旗| 大关县|