@property
裝飾器是 Python 中實(shí)現(xiàn)屬性訪問(wèn)控制的強(qiáng)大工具,它允許你將方法轉(zhuǎn)換為"動(dòng)態(tài)屬性",提供更精細(xì)的屬性訪問(wèn)控制。
在面向?qū)ο缶幊讨?,直接暴露類的屬性存在以下?wèn)題:
- 無(wú)法驗(yàn)證數(shù)據(jù):無(wú)法在賦值時(shí)檢查數(shù)據(jù)有效性
- 無(wú)法動(dòng)態(tài)計(jì)算:屬性值不能基于其他屬性動(dòng)態(tài)計(jì)算
- 破壞封裝性:外部可直接修改內(nèi)部狀態(tài)
@property
解決了這些問(wèn)題,讓你能夠:
- 在屬性訪問(wèn)時(shí)執(zhí)行自定義邏輯
- 實(shí)現(xiàn)數(shù)據(jù)驗(yàn)證
class MyClass:
def__init__(self, value):
self._value = value # 內(nèi)部使用帶下劃線的變量名
@property
defvalue(self):
"""Getter方法:訪問(wèn)屬性時(shí)調(diào)用"""
returnself._value
@value.setter
defvalue(self, new_value):
"""Setter方法:設(shè)置屬性時(shí)調(diào)用"""
if new_value < 0:
raise ValueError("值不能為負(fù)數(shù)")
self._value = new_value
@value.deleter
defvalue(self):
"""Deleter方法:刪除屬性時(shí)調(diào)用"""
print("刪除值!")
delself._value
1. 只讀屬性(無(wú) setter)
class Circle:
def__init__(self, radius):
self.radius = radius
@property
defarea(self):
"""只讀屬性:計(jì)算圓的面積"""
return3.14 * self.radius ** 2
# 使用
c = Circle(5)
print(c.area) # 78.5
c.area = 100# 報(bào)錯(cuò):AttributeError: can't set attribute
2. 數(shù)據(jù)驗(yàn)證
class Temperature:
def__init__(self, celsius):
self.celsius = celsius # 使用setter
@property
defcelsius(self):
returnself._celsius
@celsius.setter
defcelsius(self, value):
if value < -273.15:
raise ValueError("溫度不能低于絕對(duì)零度")
self._celsius = value
# 使用
temp = Temperature(25)
temp.celsius = -300# ValueError: 溫度不能低于絕對(duì)零度
3. 屬性別名
class Person:
def__init__(self, first_name, last_name):
self.first_name = first_name
self.last_name = last_name
@property
deffull_name(self):
"""動(dòng)態(tài)計(jì)算全名"""
returnf"{self.first_name} {self.last_name}"
@full_name.setter
deffull_name(self, name):
"""通過(guò)全名設(shè)置姓名"""
first, last = name.split(" ", 1)
self.first_name = first
self.last_name = last
# 使用
p = Person("張", "三")
print(p.full_name) # 張 三
p.full_name = "李 四"
print(p.first_name) # 李
1. 屬性緩存
class ExpensiveCalculation:
def__init__(self):
self._result = None
@property
defresult(self):
"""緩存計(jì)算結(jié)果"""
ifself._result isNone:
print("執(zhí)行復(fù)雜計(jì)算...")
self._result = self._calculate()
returnself._result
def_calculate(self):
# 模擬復(fù)雜計(jì)算
returnsum(range(1, 1000000))
# 使用
calc = ExpensiveCalculation()
print(calc.result) # 第一次調(diào)用會(huì)計(jì)算
print(calc.result) # 直接返回緩存結(jié)果
2. 屬性依賴
class Rectangle:
def__init__(self, width, height):
self.width = width
self.height = height
@property
defarea(self):
returnself.width * self.height
@property
defperimeter(self):
return2 * (self.width + self.height)
@property
defaspect_ratio(self):
"""寬高比(只讀)"""
returnself.width / self.height
@aspect_ratio.setter
defaspect_ratio(self, ratio):
"""通過(guò)寬高比設(shè)置尺寸,保持面積不變"""
current_area = self.area
self.width = (current_area * ratio) ** 0.5
self.height = current_area / self.width
# 使用
rect = Rectangle(4, 3)
print(f"原始尺寸: {rect.width}x{rect.height}") # 4x3
rect.aspect_ratio = 16/9
print(f"新尺寸: {rect.width:.1f}x{rect.height:.1f}") # 6.5x3.7
命名規(guī)范:
- 使用單下劃線前綴
_var
表示受保護(hù)屬性
性能考慮:
- 復(fù)雜計(jì)算應(yīng)考慮緩存結(jié)果
何時(shí)使用:
- 需要數(shù)據(jù)驗(yàn)證時(shí)
- 需要?jiǎng)討B(tài)計(jì)算屬性時(shí)
常見(jiàn)錯(cuò)誤:
class BadExample:
@property
def value(self):
return self.value # 遞歸調(diào)用自身!
@value.setter
def value(self, new_value):
self.value = new_value # 遞歸設(shè)置!
正確做法:使用帶下劃線的內(nèi)部變量
與普通屬性的區(qū)別:
選擇建議:
- 需要跨類復(fù)用相同屬性邏輯時(shí)使用描述符
配置管理系統(tǒng)
class AppConfig:
def__init__(self):
self._settings = {}
self._cache = {}
@property
deftheme(self):
"""獲取當(dāng)前主題"""
returnself._settings.get('theme', 'light')
@theme.setter
deftheme(self, value):
"""設(shè)置主題并驗(yàn)證"""
if value notin ['light', 'dark', 'system']:
raise ValueError("無(wú)效的主題選項(xiàng)")
self._settings['theme'] = value
self._cache.clear() # 清除緩存
@property
defapi_endpoint(self):
"""動(dòng)態(tài)構(gòu)建API端點(diǎn)"""
if'api_endpoint'notinself._cache:
base_url = self._settings.get('base_url', 'https://api.example.com')
version = self._settings.get('api_version', 'v1')
self._cache['api_endpoint'] = f"{base_url}/{version}/"
returnself._cache['api_endpoint']
# 使用
config = AppConfig()
config.theme = 'dark'
print(config.theme) # dark
print(config.api_endpoint) # https://api.example.com/v1/
@property
裝飾器是 Python 面向?qū)ο缶幊讨胁豢苫蛉钡墓ぞ撸?/span>
- 支持?jǐn)?shù)據(jù)驗(yàn)證和動(dòng)態(tài)計(jì)算
關(guān)鍵要點(diǎn):
- 使用
@property
定義 getter 方法 - 使用
@x.setter
定義 setter 方法 - 使用
@x.deleter
定義 deleter 方法 - 內(nèi)部使用帶下劃線變量存儲(chǔ)實(shí)際數(shù)據(jù)
- 優(yōu)先用于簡(jiǎn)單屬性邏輯,復(fù)雜場(chǎng)景考慮描述符
掌握 @property
更加 Pythonic地設(shè)計(jì)類,在保持接口簡(jiǎn)潔的同時(shí)實(shí)現(xiàn)強(qiáng)大的屬性控制功能。
閱讀原文:原文鏈接
該文章在 2025/7/18 10:34:59 編輯過(guò)