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

Python利用@property優(yōu)雅實(shí)現(xiàn)控制類成員訪問

 更新時(shí)間:2026年01月14日 14:52:36   作者:站大爺IP  
在Python面向?qū)ο缶幊讨?類成員的訪問控制是一個(gè)核心話題,@property裝飾器通過將方法偽裝成屬性,提供了一種優(yōu)雅的解決方案,下面小編就和大家詳細(xì)介紹一下吧

在Python面向?qū)ο缶幊讨校惓蓡T的訪問控制是一個(gè)核心話題。傳統(tǒng)方式通過__init__初始化屬性和直接調(diào)用方法修改屬性,雖簡(jiǎn)單直接,卻存在數(shù)據(jù)驗(yàn)證缺失、接口不統(tǒng)一等問題。@property裝飾器通過將方法偽裝成屬性,提供了一種優(yōu)雅的解決方案——既保持屬性調(diào)用的簡(jiǎn)潔性,又能實(shí)現(xiàn)數(shù)據(jù)驗(yàn)證、計(jì)算屬性、延遲加載等高級(jí)功能。

一、傳統(tǒng)訪問方式的局限:從“直接暴露”到“失控風(fēng)險(xiǎn)”

1.1 直接暴露屬性的隱患

考慮一個(gè)簡(jiǎn)單的Person類:

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

直接通過person.age = -1修改年齡時(shí),程序不會(huì)阻止這種無效操作。若年齡需限制在0-120之間,傳統(tǒng)方式需額外添加驗(yàn)證方法:

class Person:
    def __init__(self, name, age):
        self.name = name
        self.set_age(age)  # 初始化時(shí)調(diào)用驗(yàn)證方法

    def set_age(self, value):
        if 0 <= value <= 120:
            self._age = value
        else:
            raise ValueError("Age must be between 0 and 120")

    def get_age(self):
        return self._age

調(diào)用時(shí)需顯式使用get_age()set_age(),破壞了屬性訪問的直觀性。

1.2 計(jì)算屬性的需求

若需根據(jù)身高和體重計(jì)算BMI指數(shù),傳統(tǒng)方式需額外定義方法:

class HealthProfile:
    def __init__(self, height, weight):
        self.height = height  # 單位:米
        self.weight = weight  # 單位:千克

    def calculate_bmi(self):
        return self.weight / (self.height ** 2)

每次獲取BMI都需調(diào)用calculate_bmi(),不如直接訪問health.bmi直觀。

1.3 延遲加載的必要性

對(duì)于耗時(shí)操作(如從數(shù)據(jù)庫(kù)加載數(shù)據(jù)),若在初始化時(shí)立即執(zhí)行,會(huì)降低程序性能。理想方式是在首次訪問時(shí)才加載數(shù)據(jù),但直接屬性無法實(shí)現(xiàn)這種延遲初始化。

二、@property的核心機(jī)制:方法與屬性的“變身術(shù)”

2.1 基本語法:從方法到屬性

@property裝飾器將方法轉(zhuǎn)換為屬性,調(diào)用時(shí)無需括號(hào):

class Person:
    def __init__(self, name, age):
        self.name = name
        self._age = age  # 使用下劃線約定“受保護(hù)”屬性

    @property
    def age(self):
        return self._age

    @age.setter
    def age(self, value):
        if 0 <= value <= 120:
            self._age = value
        else:
            raise ValueError("Age must be between 0 and 120")

現(xiàn)在可通過person.age = 25設(shè)置年齡,若嘗試賦值為-1會(huì)觸發(fā)異常,同時(shí)仍可通過person.age獲取值,接口與普通屬性完全一致。

2.2 裝飾器鏈的完整結(jié)構(gòu)

@property體系包含三個(gè)裝飾器:

  • @property:定義getter方法
  • @property_name.setter:定義setter方法
  • @property_name.deleter:定義deleter方法(可選)

完整示例:

class Circle:
    def __init__(self, radius):
        self._radius = radius

    @property
    def radius(self):
        return self._radius

    @radius.setter
    def radius(self, value):
        if value > 0:
            self._radius = value
        else:
            raise ValueError("Radius must be positive")

    @radius.deleter
    def radius(self):
        del self._radius  # 實(shí)際開發(fā)中需謹(jǐn)慎使用

2.3 只讀屬性的實(shí)現(xiàn)

若只需限制屬性為只讀,可省略setter方法:

class Temperature:
    def __init__(self, celsius):
        self._celsius = celsius

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

    @property
    def fahrenheit(self):
        return self._celsius * 9 / 5 + 32

temp = Temperature(25)
print(temp.fahrenheit)  # 輸出77.0
temp.fahrenheit = 100   # 觸發(fā)AttributeError: can't set attribute

三、@property的典型應(yīng)用場(chǎng)景:從驗(yàn)證到優(yōu)化

3.1 數(shù)據(jù)驗(yàn)證:守護(hù)屬性的合法性

@property最常用的場(chǎng)景是數(shù)據(jù)驗(yàn)證。例如,確保用戶名只包含字母和數(shù)字:

class User:
    def __init__(self, username):
        self._username = username

    @property
    def username(self):
        return self._username

    @username.setter
    def username(self, value):
        if not value.isalnum():
            raise ValueError("Username must contain only letters and numbers")
        self._username = value

3.2 計(jì)算屬性:動(dòng)態(tài)生成數(shù)據(jù)

對(duì)于需要根據(jù)其他屬性計(jì)算的動(dòng)態(tài)值,@property可避免重復(fù)計(jì)算:

class Rectangle:
    def __init__(self, width, height):
        self._width = width
        self._height = height

    @property
    def area(self):
        return self._width * self._height

    @property
    def perimeter(self):
        return 2 * (self._width + self._height)

rect = Rectangle(4, 5)
print(rect.area)      # 輸出20
print(rect.perimeter) # 輸出18

3.3 延遲加載:優(yōu)化性能的關(guān)鍵

對(duì)于耗時(shí)操作,@property可實(shí)現(xiàn)按需加載:

class DatabaseQuery:
    def __init__(self, query):
        self._query = query
        self._data = None

    @property
    def data(self):
        if self._data is None:
            print("Executing query...")
            self._data = f"Result for {self._query}"  # 模擬數(shù)據(jù)庫(kù)查詢
        return self._data

query = DatabaseQuery("SELECT * FROM users")
print(query.data)  # 首次訪問執(zhí)行查詢
print(query.data)  # 后續(xù)訪問直接返回緩存結(jié)果

3.4 屬性別名:保持向后兼容

當(dāng)需要重構(gòu)代碼但不想破壞現(xiàn)有接口時(shí),@property可創(chuàng)建屬性別名:

class LegacySystem:
    def __init__(self, old_param):
        self._new_param = old_param * 2  # 新實(shí)現(xiàn)需要乘以2

    @property
    def old_param(self):
        return self._new_param / 2  # 保持與舊接口一致

    @old_param.setter
    def old_param(self, value):
        self._new_param = value * 2  # 自動(dòng)轉(zhuǎn)換后存儲(chǔ)

四、@property的進(jìn)階技巧:從設(shè)計(jì)到優(yōu)化

4.1 鏈?zhǔn)綄傩栽L問:構(gòu)建流暢接口

結(jié)合@property和返回值設(shè)計(jì),可實(shí)現(xiàn)鏈?zhǔn)秸{(diào)用:

class QueryBuilder:
    def __init__(self):
        self._query = []

    @property
    def select(self):
        def inner(columns):
            self._query.append(f"SELECT {', '.join(columns)}")
            return self
        return inner

    @property
    def from_table(self):
        def inner(table):
            self._query.append(f"FROM {table}")
            return self
        return inner

    def execute(self):
        return " ".join(self._query)

query = QueryBuilder().select(["id", "name"]).from_table("users").execute()
print(query)  # 輸出: SELECT id, name FROM users

4.2 類型注解:提升代碼可讀性

Python 3.6+支持為@property添加類型注解:

from typing import Optional

class Product:
    def __init__(self, price: float):
        self._price = price

    @property
    def price(self) -> float:
        return self._price

    @price.setter
    def price(self, value: float) -> None:
        if value < 0:
            raise ValueError("Price cannot be negative")
        self._price = value

4.3 性能優(yōu)化:避免過度使用

@property雖優(yōu)雅,但存在性能開銷。對(duì)于頻繁訪問的簡(jiǎn)單屬性,直接訪問可能更快:

import timeit

class DirectAccess:
    def __init__(self):
        self.value = 42

class PropertyAccess:
    def __init__(self):
        self._value = 42

    @property
    def value(self):
        return self._value

direct = DirectAccess()
property_obj = PropertyAccess()

# 測(cè)試直接訪問
direct_time = timeit.timeit(lambda: direct.value, number=1000000)
# 測(cè)試屬性訪問
property_time = timeit.timeit(lambda: property_obj.value, number=1000000)

print(f"Direct access: {direct_time:.6f}s")
print(f"Property access: {property_time:.6f}s")

在筆者的測(cè)試環(huán)境中,直接訪問比屬性訪問快約20%。對(duì)于性能敏感的場(chǎng)景,需權(quán)衡可讀性與性能。

4.4 與@cached_property結(jié)合:記憶化計(jì)算屬性

Python 3.8+的functools.cached_property可緩存計(jì)算屬性的結(jié)果:

from functools import cached_property

class ExpensiveCalculation:
    def __init__(self, x):
        self.x = x

    @cached_property
    def result(self):
        print("Calculating...")
        return self.x ** 2  # 模擬耗時(shí)計(jì)算

calc = ExpensiveCalculation(5)
print(calc.result)  # 輸出: Calculating... \n 25
print(calc.result)  # 直接返回緩存結(jié)果25

五、@property的替代方案:何時(shí)選擇其他方式

5.1 直接屬性:簡(jiǎn)單場(chǎng)景的首選

對(duì)于無需驗(yàn)證、計(jì)算的簡(jiǎn)單屬性,直接使用實(shí)例變量更簡(jiǎn)潔:

class Point:
    def __init__(self, x, y):
        self.x = x  # 直接暴露
        self.y = y

5.2 描述符協(xié)議:更底層的控制

需要更復(fù)雜控制時(shí),可實(shí)現(xiàn)描述符協(xié)議(__get____set____delete__):

class NonNegative:
    def __set__(self, instance, value):
        if value < 0:
            raise ValueError("Value must be non-negative")
        instance.__dict__[self.name] = value

    def __set_name__(self, owner, name):
        self.name = name

class Model:
    age = NonNegative()

    def __init__(self, age):
        self.age = age

model = Model(25)
model.age = -1  # 觸發(fā)ValueError

5.3dataclasses:快速定義數(shù)據(jù)類

Python 3.7+的@dataclass裝飾器可自動(dòng)生成__init__等方法:

from dataclasses import dataclass

@dataclass
class InventoryItem:
    name: str
    unit_price: float
    quantity_on_hand: int = 0

    @property
    def total_value(self):
        return self.unit_price * self.quantity_on_hand

六、最佳實(shí)踐:編寫健壯的@property代碼

6.1 命名約定:使用下劃線前綴

遵循Python約定,受保護(hù)的內(nèi)部屬性使用單下劃線前綴:

class BankAccount:
    def __init__(self, balance):
        self._balance = balance  # 表明這是內(nèi)部屬性

    @property
    def balance(self):
        return self._balance

6.2 避免循環(huán)引用:防止無限遞歸

在getter或setter中訪問屬性自身時(shí)需謹(jǐn)慎:

class BrokenExample:
    def __init__(self):
        self._value = 0

    @property
    def value(self):
        return self.value  # 錯(cuò)誤:無限遞歸

# 正確寫法
class FixedExample:
    def __init__(self):
        self._value = 0

    @property
    def value(self):
        return self._value

6.3 文檔字符串:說明屬性用途

@property方法添加文檔字符串,提高代碼可維護(hù)性:

class TemperatureConverter:
    def __init__(self, celsius):
        self._celsius = celsius

    @property
    def kelvin(self):
        """Get temperature in Kelvin.
        
        Formula: K = °C + 273.15
        """
        return self._celsius + 273.15

6.4 異常處理:提供有意義的錯(cuò)誤信息

在setter中驗(yàn)證數(shù)據(jù)時(shí),拋出具體的異常:

class DateRange:
    def __init__(self, start, end):
        self.start = start  # 通過setter驗(yàn)證
        self.end = end

    @property
    def start(self):
        return self._start

    @start.setter
    def start(self, value):
        if not isinstance(value, str):
            raise TypeError("Start date must be a string")
        if len(value) != 10:
            raise ValueError("Start date must be in YYYY-MM-DD format")
        self._start = value

七、總結(jié):@property的核心價(jià)值與應(yīng)用哲學(xué)

@property通過裝飾器機(jī)制,在保持屬性調(diào)用語法的同時(shí),賦予了方法級(jí)的控制能力。其核心價(jià)值體現(xiàn)在:

  • 封裝性:隱藏內(nèi)部實(shí)現(xiàn)細(xì)節(jié),暴露簡(jiǎn)潔接口
  • 安全性:通過數(shù)據(jù)驗(yàn)證防止無效狀態(tài)
  • 靈活性:支持計(jì)算屬性、延遲加載等高級(jí)特性
  • 兼容性:無縫替代原有屬性訪問方式

在實(shí)際開發(fā)中,應(yīng)遵循“適度使用”原則:

  • 對(duì)需要驗(yàn)證、計(jì)算的屬性使用@property
  • 對(duì)簡(jiǎn)單屬性直接暴露
  • 在性能敏感場(chǎng)景權(quán)衡可讀性與效率

掌握@property后,可進(jìn)一步探索描述符協(xié)議、元類等高級(jí)特性,構(gòu)建更健壯的Python對(duì)象模型。正如Python之禪所言:“簡(jiǎn)單優(yōu)于復(fù)雜”,@property正是這種哲學(xué)在屬性訪問控制上的完美體現(xiàn)。

到此這篇關(guān)于Python利用@property優(yōu)雅實(shí)現(xiàn)控制類成員訪問的文章就介紹到這了,更多相關(guān)Python @property控制類成員訪問內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Python中最好用的json庫(kù)orjson用法詳解

    Python中最好用的json庫(kù)orjson用法詳解

    orjson是一個(gè)用于python的快速、正確的json庫(kù),它的基準(zhǔn)是 json最快的python庫(kù),具有全面的單元、集成和互操作性測(cè)試,下面這篇文章主要給大家介紹了關(guān)于Python中最好用的json庫(kù)orjson用法的相關(guān)資料,需要的朋友可以參考下
    2022-06-06
  • 將pytorch轉(zhuǎn)成longtensor的簡(jiǎn)單方法

    將pytorch轉(zhuǎn)成longtensor的簡(jiǎn)單方法

    今天小編就為大家分享一篇將pytorch轉(zhuǎn)成longtensor的簡(jiǎn)單方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-02-02
  • Python tkinter三種布局實(shí)例詳解

    Python tkinter三種布局實(shí)例詳解

    這篇文章主要介紹了Python tkinter三種布局實(shí)例詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-01-01
  • python使用tcp實(shí)現(xiàn)局域網(wǎng)內(nèi)文件傳輸

    python使用tcp實(shí)現(xiàn)局域網(wǎng)內(nèi)文件傳輸

    這篇文章主要介紹了python使用tcp實(shí)現(xiàn)局域網(wǎng)內(nèi)文件傳輸,文件包括文本,圖片,視頻等,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-07-07
  • 使用Pandas實(shí)現(xiàn)高效讀取篩選csv數(shù)據(jù)

    使用Pandas實(shí)現(xiàn)高效讀取篩選csv數(shù)據(jù)

    在數(shù)據(jù)分析和數(shù)據(jù)科學(xué)領(lǐng)域中,Pandas?是?Python?中最常用的庫(kù)之一,本文將介紹如何使用?Pandas?來讀取和處理?CSV?格式的數(shù)據(jù)文件,希望對(duì)大家有所幫助
    2024-04-04
  • Opencv-Python圖像透視變換cv2.warpPerspective的示例

    Opencv-Python圖像透視變換cv2.warpPerspective的示例

    今天小編就為大家分享一篇關(guān)于Opencv-Python圖像透視變換cv2.warpPerspective的示例,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧
    2019-04-04
  • Python3日期與時(shí)間戳轉(zhuǎn)換的幾種方法詳解

    Python3日期與時(shí)間戳轉(zhuǎn)換的幾種方法詳解

    我們可以利用內(nèi)置模塊 datetime 獲取當(dāng)前時(shí)間,然后將其轉(zhuǎn)換為對(duì)應(yīng)的時(shí)間戳。這篇文章主要介紹了Python3日期與時(shí)間戳轉(zhuǎn)換的幾種方法,需要的朋友可以參考下
    2019-06-06
  • python多線程http下載實(shí)現(xiàn)示例

    python多線程http下載實(shí)現(xiàn)示例

    python多線程http下載實(shí)現(xiàn)示例,大家參考使用吧
    2013-12-12
  • Python實(shí)現(xiàn)的最近最少使用算法

    Python實(shí)現(xiàn)的最近最少使用算法

    這篇文章主要介紹了Python實(shí)現(xiàn)的最近最少使用算法,涉及節(jié)點(diǎn)、時(shí)間、流程控制等相關(guān)技巧,需要的朋友可以參考下
    2015-07-07
  • 三種Matplotlib中動(dòng)態(tài)更新繪圖的方法總結(jié)

    三種Matplotlib中動(dòng)態(tài)更新繪圖的方法總結(jié)

    這篇文章主要為大家詳細(xì)介紹了如何隨著數(shù)據(jù)的變化動(dòng)態(tài)更新Matplotlib(Python的數(shù)據(jù)可視化庫(kù))圖,文中介紹了常用的三種方法,希望對(duì)大家有所幫助
    2024-04-04

最新評(píng)論

宜黄县| 安泽县| 吉水县| 南川市| 永济市| 德惠市| 连云港市| 瑞金市| 喀喇沁旗| 张家界市| 于都县| 罗城| 陇南市| 汉阴县| 将乐县| 宜君县| 法库县| 扶绥县| 通河县| 江川县| 化德县| 宜城市| 大埔区| 安丘市| 嘉禾县| 深圳市| 华池县| 云和县| 绩溪县| 喜德县| 龙州县| 宣威市| 岳池县| 伽师县| 灵台县| 无极县| 河东区| 洱源县| 外汇| 田阳县| 通渭县|