Python 面向對象實戰:私有屬性與公有屬性的最佳實踐——用線段類舉例

在這里插入圖片描述

描述

在繪圖軟件、GIS、CAD 或簡單的圖形編輯器中,線段(Segment)是非常基礎的對象。每個線段有兩個端點(x1,y1)和(x2,y2)。在實現時我們通常希望:

  • 封裝端點數據(防止外部隨意改寫造成不一致),比如修改端點后需要自動更新某些內部緩存或做驗證(不能產生零長度線段等)。
  • 統計創建了多少線段(類層面的統計),但又不想讓外部隨意改這個計數(增加/減小計數會破壞統計)。
  • 允許外部讀取一些信息(比如用于 UI 顯示的公開計數,或線段的標簽),同時對寫操作做控制(通過方法或屬性 setter 做驗證)。

Python 中通過“以兩個下劃線開頭但不以兩個下劃線結尾”的名字,會觸發名稱改寫(name mangling),能夠在一定程度上把屬性“隱藏”到類作用域下(并非絕對私有,但能避免偶然覆蓋/訪問)。本文以 Segment 類為例實現上述需求,并演示私有/公有屬性的典型用法與注意點。

題解答案(完整可運行代碼)

# segment_example.py
import mathclass Segment:"""表示二維平面上的一條線段(端點私有,部分類屬性私有/公有示例)"""# 私有類屬性:名稱以兩個下劃線開頭(但不以兩個下劃線結尾)__secret_count = 0# 公有類屬性:外部可以直接讀寫(但請謹慎寫)public_count = 0def __init__(self, x1=0, y1=0, x2=0, y2=0, label=None):# 私有實例屬性(用雙下劃線名字,會被 name-mangle 成 _Segment__x1 等)self.__x1 = float(x1)self.__y1 = float(y1)self.__x2 = float(x2)self.__y2 = float(y2)# 公有實例屬性(習慣上可被外部直接訪問)self.label = label# 每創建一個實例就更新統計(通過類名訪問私有類屬性)Segment.__secret_count += 1Segment.public_count += 1# 驗證:不允許零長度的線段(舉例業務規則)if self.length() == 0:raise ValueError("不允許零長度線段:兩個端點不能相同")# ---------- 公有方法:訪問/修改私有數據 -----------def set_points(self, x1, y1, x2, y2):"""設置端點(會做基本驗證)"""x1, y1, x2, y2 = float(x1), float(y1), float(x2), float(y2)if x1 == x2 and y1 == y2:raise ValueError("不允許把兩個端點設置為相同坐標(零長度)")self.__x1, self.__y1, self.__x2, self.__y2 = x1, y1, x2, y2def get_points(self):"""返回端點坐標的元組(只讀視圖)"""return (self.__x1, self.__y1, self.__x2, self.__y2)def length(self):"""返回線段長度(Euclidean distance)"""dx = self.__x2 - self.__x1dy = self.__y2 - self.__y1return math.hypot(dx, dy)def midpoint(self):"""返回線段中點坐標"""return ((self.__x1 + self.__x2) / 2.0, (self.__y1 + self.__y2) / 2.0)def translate(self, dx, dy):"""平移線段(原地修改)"""self.__x1 += dxself.__y1 += dyself.__x2 += dxself.__y2 += dy# ---------- 類方法 / 靜態方法 -----------@classmethoddef get_public_count(cls):"""返回公有計數(等價于直接訪問 cls.public_count)"""return cls.public_count@classmethoddef get_secret_count(cls):"""返回私有計數(提供受控訪問)"""return cls.__secret_countdef __repr__(self):p = self.get_points()return f"Segment(({p[0]}, {p[1]}), ({p[2]}, {p[3]}), label={self.label!r})"

題解代碼分析

下面逐個解釋代碼重點,幫助你真正理解私有與公有屬性的選擇和用法。

私有類屬性 __secret_count

__secret_count = 0
  • 這是類級別的屬性。因為以兩個下劃線開頭,它會被 Python 改名(name-mangling)為 _Segment__secret_count(內部實現),從而在外部直接用 Segment.__secret_count 訪問會報錯。
  • 設計初衷是:統計創建的實例數,但不希望外部隨意改寫這個統計值(雖然可以通過 name-mangling 強行訪問)。為了安全、規范,類里同時提供了公有的 public_count(可被 UI 展示)和受控的 get_secret_count() 來讀取私有值。

公有類屬性 public_count

public_count = 0
  • 這是公開的類屬性,外部可直接訪問 Segment.public_count。我們把它作為“展示用”的計數:即使外部能改它,設計上是允許展示、輕量讀寫,但關鍵邏輯仍然被私有計數保護。

私有實例屬性 __x1, __y1, __x2, __y2

self.__x1 = float(x1)
...
  • 這些屬性存儲端點坐標。以雙下劃線開頭,它們在類外不會以原名出現,會被改寫成 _Segment__x1 等。
  • 這樣可以降低外部代碼不小心直接賦值造成狀態不一致的可能性(例如直接把 s.__x1 改成字符串)。如果真的需要外部控制坐標,應該通過 set_points() 或者用 @property/setter 做合法性檢查。

構造函數里的驗證

if self.length() == 0:raise ValueError("不允許零長度線段:兩個端點不能相同")
  • 這是業務規則示例:不允許零長度線段。封裝私有數據的好處在此體現:我們能在構造/設置時統一做驗證,保證類狀態始終合法。

訪問與修改接口

  • get_points():提供只讀視圖,返回端點元組;
  • set_points():提供受控修改,內部做驗證;
  • length() / midpoint() / translate():這些都是典型的對象行為,直接在私有字段上操作,不暴露實現細節。

類方法 get_secret_countget_public_count

  • 即便有私有類屬性,我們仍然提供受控的讀取接口,既能保護數據,又能讓調用者獲得需要的信息。

名稱改寫(name mangling)說明

  • 私有屬性并不是絕對隱藏。實際上,屬性名 __x1 在類定義內部會被解釋器改寫成 _Segment__x1。你可以從外部通過 instance._Segment__x1 訪問,但這不被推薦,僅用于調試或特殊場景。
  • 規則回顧:如果名字以兩個下劃線開頭不以兩個下劃線結尾(即不是 dunder 方法),就會觸發 name mangling。像 __init__ 不會被“私有化”,因為它以兩個下劃線開頭但也以兩個下劃線結尾(這是魔法方法/特殊方法)。

示例測試及結果

下面給出一系列示例用法,并展示運行結果(假定把上面類存為 segment_example.py 或直接在 REPL 執行)。

# 示例 1:創建一個正常線段
s = Segment(0, 0, 3, 4, label="A-B")
print(s)                       # 調用 __repr__
print("端點:", s.get_points())
print("長度:", s.length())
print("中點:", s.midpoint())
print("類的公有計數:", Segment.public_count)
print("通過類方法看公有計數:", Segment.get_public_count())
print("通過類方法看私有計數:", Segment.get_secret_count())# 示例 2:平移后驗證
s.translate(1, 1)
print("平移后端點:", s.get_points())
print("平移后長度(應保持不變):", s.length())# 示例 3:嘗試創建零長度線段(應拋異常)
try:bad = Segment(0, 0, 0, 0)
except ValueError as e:print("創建零長度線段失敗:", e)# 示例 4:演示不推薦但可行的私有屬性訪問(name-mangling)
print("私有屬性(name-mangle) x1:", s._Segment__x1)
print("私有類計數(name-mangle):", Segment._Segment__secret_count)

預期輸出(示例)

Segment((0.0, 0.0), (3.0, 4.0), label='A-B')
端點: (0.0, 0.0, 3.0, 4.0)
長度: 5.0
中點: (1.5, 2.0)
類的公有計數: 1
通過類方法看公有計數: 1
通過類方法看私有計數: 1
平移后端點: (1.0, 1.0, 4.0, 5.0)
平移后長度(應保持不變): 5.0
創建零長度線段失敗: 不允許零長度線段:兩個端點不能相同
私有屬性(name-mangle) x1: 1.0
私有類計數(name-mangle): 1

注意:最后兩個打印演示的是“可以通過 name-mangle 訪問私有數據,但這屬于越過封裝的做法,不建議在正常業務邏輯中使用”。

時間復雜度

Segment 中常用操作的時間復雜度分析(按單次調用計):

  • __init__:O(1) —— 創建實例、賦值、做一次長度計算(常數時間)。
  • get_points():O(1) —— 返回 4 元素元組。
  • set_points():O(1) —— 驗證并賦值(常數時間)。
  • length():O(1) —— 常數次算術運算和 math.hypot
  • midpoint():O(1) —— 常數時間。
  • translate(dx, dy):O(1) —— 常數次賦值。

總體上,這個類的基本操作都是 O(1)。如果你的應用需要對大量線段做批量操作(比如 N 條線段做碰撞檢測),那整體復雜度會依據具體算法提升(例如 O(N^2) 的暴力檢測等),但這超出當前類設計范疇。

空間復雜度

單個 Segment 實例占用常數空間:保存 4 個浮點數、少量額外元數據與一個 label 引用(如果提供)。因此單個對象的空間復雜度是 O(1)。

若有 NSegment 對象,總空間大致為 O(N)。

總結

  • 使用雙下劃線前綴(例如 __x1)可以觸發 Python 的 name-mangling,從而把屬性名“隱藏”在類的內部,減少外部無意的覆蓋和誤用,但并非絕對不可訪問。私有屬性用于實現數據封裝、保證內部一致性與提供受控訪問。
  • 公有屬性(例如 public_countlabel)適合用于需要頻繁讀取、用于 UI 展示或允許用戶直接定制的內容,但一旦允許寫入,就需要在設計上容忍或校驗它的變更。
  • 在實際場景(繪圖工具、幾何計算、地圖標注等)中,把核心數據設為私有、對外提供受控方法是一個良好的工程實踐。這樣能把內部實現與外部接口解耦,便于以后修改實現(例如改用向量緩存、懶計算等)而不會影響外部代碼。
  • 如果需要嚴格不可變的屬性,可以在外層加封裝(例如只讀 property、或使用 @dataclass(frozen=True) 的變體),但那又是另一種設計取舍。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/96253.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/96253.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/96253.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

流式細胞術樣本處理全攻略(一):組織、血液、體液制備方法詳解

摘要 流式細胞術作為多參數、高通量的細胞分析技術,在細胞表型鑒定、免疫反應研究、疾病機制探索及藥物效果評估中發揮關鍵作用。而樣本制備是流式實驗成功的核心前提,需將不同來源樣本處理為單顆粒懸液,并最大程度減少細胞死亡與碎片干擾。本文針對組織、外周血 / 骨髓、體…

【C#】理解.NET內存機制:堆、棧與裝箱拆箱的底層邏輯及優化技巧

文章目錄前言一、棧與堆1.1 棧(Stack)1.1.1 基本信息1.1.2 特點1.2 堆(Heap)1.2.1 基本信息1.2.2 特點1.3 從代碼中窺見堆棧二、裝箱與拆箱2.1 裝箱2.2 拆箱2.3 如何避免不必要的裝箱與拆箱2.3.1 泛型集合2.3.2 泛型參數總結前言 …

人工智能學習:Transformer結構中的子層連接(Sublayer Connection)

Transformer結構中的子層連接(Sublayer Connection) 一、子層連接介紹 概念 子層連接(Sublayer Connection),也稱為殘差連接(Residual Connection),是Transformer模型中的一個關鍵設計,用于將多個子層(如自注意力層和前饋全連接層)組合在一起。它通過殘差連…

解鎖Roo Code的強大功能:深入理解上下文提及(Context Mentions)

在AI使用中,我們經常需要AI或AI工具描述代碼中的某個具體部分。但如果工具能直接“看到”所指的代碼、錯誤信息甚至終端輸出,協作效率會不會大幅提升?這正是 Roo Code 的“上下文提及(Context Mentions)”功能所要實現…

第5篇、 Kafka 數據可靠性與容錯機制

在分布式消息隊列系統中,數據可靠性 與 容錯能力 是核心指標。Kafka 作為高吞吐、可擴展的流式處理平臺,依靠副本復制、Leader 選舉和 ISR 機制,保證了在節點故障時消息依然能夠可靠傳輸與消費。 📚 目錄 理論基礎 一、數據復制…

Excel表格如何制作?【圖文詳解】表格Excel制作教程?電腦Excel表格制作?

一、問題背景 在日常辦公中,無論是統計數據、整理報表,還是記錄信息,Excel表格都是必不可少的工具。 但對新手來說,打開Excel后面對空白的單元格,常常不知道從何下手——不知道怎么選表格范圍、怎么加邊框讓表格顯形、…

阿里兵臨城下,美團迎來至暗時刻?

9月10日,趕在阿里巴巴成立26周年之際,高德地圖推出了首個基于用戶行為產生的榜單“高德掃街榜”,被定義為“阿里生活服務超級新入口”,試圖重新構建一套線下服務的信用體系。 上線第二天,就有媒體報道稱“使用高德掃街…

Android逆向學習(十一) IDA動態調試Android so文件

Android逆向學習(十一) IDA動態調試Android so文件 一、 寫在前面 這是吾愛破解論壇正己大大的第12個教程,并且發現一個神奇的事情,正己大大的教程竟然沒有第11個,感覺很奇怪 寫這個博客的主要原因是希望提供一種新的解…

Django全棧班v1.03 Linux常用命令 20250911 下午

課程定位 命令行 ! 黑客專屬。 這套視頻帶你從Linux小白到命令行大師,涵蓋文件管理文本處理系統監控網絡操作。 零基礎也能30分鐘掌握程序員必備的技能。 課程亮點 1、零基礎友好:從最基礎的ls,cd命令開始,循序漸進 2、實戰導向&a…

離線應用開發:Service Worker 與緩存

引言:離線應用開發在 Electron 中的 Service Worker 與緩存核心作用與必要性 在 Electron 框架的開發實踐中,離線應用開發是提升用戶體驗和應用可用性的關鍵技術,特別是使用 Service Worker 實現緩存和離線功能,結合 Node.js 處理…

英發睿能闖關上市:業績波動明顯,毅達創投退出,臨場“移民”

撰稿|張君來源|貝多商業&貝多財經近日,四川英發睿能科技股份有限公司(下稱“英發睿能”)遞交招股書,報考在港交所上市。據貝多商業&貝多財經了解,英發睿能還于9月3日披露《整體協調人公告-委任&…

Elixir通過Onvif協議控制IP攝像機,ExOnvif庫給視頻流疊加字符

Elixir 通過 ExOnvif 庫,Onvif 協議可以控制IP攝像機等設備,這篇文章記錄:使用ExOnvif庫,給視頻流疊加文字,使用ExOnvif庫的接口模塊:ExOnvif.Media、ExOnvif.Media2。 ExOnvif官方文檔 此文章內容&#xf…

線程安全相關的注解

主要有下面三個加在類上的線程安全相關的注解。一.Immutable標記一個類為不可變的。這意味著該類的實例在構造完成后,其狀態(數據)永遠不能被更改。實現不可變性的嚴格條件(Java內存模型中的定義):所有字段…

基于Springboot + vue3實現的在線智慧考公系統

項目描述本系統包含管理員、教師、用戶三個角色。管理員角色:用戶管理:管理系統中所有用戶的信息,包括添加、刪除和修改用戶。配置管理:管理系統配置參數,如上傳圖片的路徑等。權限管理:分配和管理不同角色…

賦能高效設計:12套中后臺管理信息系統通用原型框架

中后臺管理信息系統是企業數字化轉型的核心引擎,肩負著提升運營效率、賦能精準決策的重任。面對多樣化的業務場景和復雜的邏輯需求,如何快速、高質量地完成系統設計與原型構建,成為產品、設計與開發團隊共同面臨的挑戰。 為此,一套…

LangGraph中ReAct模式的深度解析:推理與行動的完美融合——從理論到實踐的智能Agent構建指南

在人工智能的演進歷程中,ReAct(Reasoning and Acting)模式無疑是最具革命性的突破之一。它不僅僅是一種技術實現,更是對智能Agent思維模式的深刻重構。而LangGraph,作為這一理念的優秀實踐者,將ReAct模式演…

蜂窩物聯網模組在換電柜場景的發展前景分析

蜂窩物聯網模組在換電柜場景中正迎來爆發式增長機遇,特別是在Cat.1技術路線主導的市場格局下,其應用價值已從基礎通信服務拓展至安全監測、智能管理、電池溯源等核心領域,成為換電柜行業標準化、智能化升級的關鍵技術支撐。隨著2025年新國標全…

機器學習之K折交叉驗證

為了更好的評估機器學習訓練出模型的泛化能力,即避免模型在訓練集上表現良好,但在未見過的數據上表現不佳(即過擬合),同時也減少了單一訓練/測試集劃分帶來的隨機性影響。一、什么是K折交叉驗證?1、將數據集…

詳細解讀k8s的kind中service與pod的區別

Pod 是運行應用實例的“容器”,而 Service 是訪問這些 Pod 的“穩定網絡門戶”。Pod(容器組)1. 核心概念: Pod 是 Kubernetes 中可以創建和管理的最小、最簡單的計算單元。一個 Pod 代表集群上正在運行的一個工作負載實例。2. 職責…

python---PyInstaller(將Python腳本打包為可執行文件)

在Python開發中,我們常需要將腳本分享給不熟悉Python環境的用戶。此時,直接提供.py文件需要對方安裝Python解釋器和依賴庫,操作繁瑣。PyInstaller作為一款主流的Python打包工具,能將腳本及其依賴打包為單個可執行文件(…