Python內(nèi)置函數(shù)之property函數(shù)用法詳解
在 Python 中,property 是一個(gè)內(nèi)置的裝飾器,用于將類方法轉(zhuǎn)換為類屬性,實(shí)現(xiàn)對(duì)屬性的高級(jí)控制(如類型檢查、只讀限制、計(jì)算屬性等)。
以下是對(duì) property 的詳細(xì)解析與實(shí)戰(zhàn)案例:
一、核心概念與基礎(chǔ)語法
1.property的本質(zhì)
- 屬性封裝:將方法偽裝成屬性,通過點(diǎn)號(hào)(
.)直接訪問 - 訪問控制:自定義屬性的 getter、setter 和 deleter 方法
- 計(jì)算屬性:動(dòng)態(tài)計(jì)算屬性值,無需顯式存儲(chǔ)
2. 基礎(chǔ)語法(兩種方式)
# 方式1:使用 property() 函數(shù)
class Person:
def __init__(self, age):
self._age = age # 私有屬性
def get_age(self):
return self._age
def set_age(self, value):
if value < 0:
raise ValueError("年齡不能為負(fù)數(shù)")
self._age = value
age = property(get_age, set_age) # 創(chuàng)建 property 對(duì)象
# 方式2:使用裝飾器(推薦)
class Person:
def __init__(self, age):
self._age = age
@property # 相當(dāng)于 age = property(age)
def age(self):
return self._age
@age.setter # 相當(dāng)于 age = age.setter(setter)
def age(self, value):
if value < 0:
raise ValueError("年齡不能為負(fù)數(shù)")
self._age = value
3. 使用示例
p = Person(25) print(p.age) # 調(diào)用 getter 方法,輸出: 25 p.age = 30 # 調(diào)用 setter 方法 p.age = -5 # 拋出 ValueError: 年齡不能為負(fù)數(shù)
二、進(jìn)階用法
1. 只讀屬性(僅實(shí)現(xiàn) getter)
class Circle:
def __init__(self, radius):
self.radius = radius
@property
def area(self):
return 3.14 * self.radius ** 2
c = Circle(5)
print(c.area) # 輸出: 78.5
c.area = 100 # 報(bào)錯(cuò): AttributeError: can't set attribute
2. 計(jì)算屬性(動(dòng)態(tài)計(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)
r = Rectangle(3, 4)
print(r.area) # 輸出: 12
print(r.perimeter) # 輸出: 14
3. 刪除屬性(實(shí)現(xiàn) deleter)
class Person:
def __init__(self, name):
self._name = name
@property
def name(self):
return self._name
@name.deleter
def name(self):
print("刪除名字...")
del self._name
p = Person("Alice")
print(p.name) # 輸出: Alice
del p.name # 輸出: 刪除名字...
print(p.name) # 報(bào)錯(cuò): AttributeError
4. 類型檢查與驗(yàn)證
class Temperature:
def __init__(self, celsius):
self.celsius = celsius
@property
def celsius(self):
return self._celsius
@celsius.setter
def celsius(self, value):
if not isinstance(value, (int, float)):
raise TypeError("溫度必須是數(shù)字")
self._celsius = value
@property
def fahrenheit(self):
return self._celsius * 1.8 + 32
t = Temperature(25)
print(t.fahrenheit) # 輸出: 77.0
t.celsius = "30" # 報(bào)錯(cuò): TypeError
三、實(shí)戰(zhàn)案例
1. 數(shù)據(jù)庫字段映射
class User:
def __init__(self, db_row):
self._db_row = db_row
@property
def id(self):
return self._db_row["id"]
@property
def username(self):
return self._db_row["username"]
@property
def email(self):
return self._db_row["email"]
# 使用示例
db_data = {"id": 1, "username": "john", "email": "john@example.com"}
user = User(db_data)
print(user.username) # 輸出: john
2. 緩存計(jì)算結(jié)果
import math
class Factorial:
def __init__(self, number):
self.number = number
self._result = None
@property
def result(self):
if self._result is None:
print("計(jì)算階乘...")
self._result = math.factorial(self.number)
return self._result
f = Factorial(5)
print(f.result) # 輸出: 計(jì)算階乘... 120
print(f.result) # 直接返回緩存結(jié)果: 120
3. 權(quán)限控制
class Account:
def __init__(self, balance, owner):
self._balance = balance
self._owner = owner
@property
def balance(self):
return self._balance
@balance.setter
def balance(self, value):
if self._owner != "admin":
raise PermissionError("只有管理員可以修改余額")
self._balance = value
acc = Account(1000, "user")
print(acc.balance) # 輸出: 1000
acc.balance = 2000 # 報(bào)錯(cuò): PermissionError
四、深入理解與注意事項(xiàng)
1.property的底層實(shí)現(xiàn)
property 是一個(gè)描述符(descriptor)類,其簡化實(shí)現(xiàn)如下:
class Property:
def __init__(self, fget=None, fset=None, fdel=None):
self.fget = fget
self.fset = fset
self.fdel = fdel
def __get__(self, instance, owner):
if instance is None:
return self
if self.fget is None:
raise AttributeError("unreadable attribute")
return self.fget(instance)
def __set__(self, instance, value):
if self.fset is None:
raise AttributeError("can't set attribute")
self.fset(instance, value)
def __delete__(self, instance):
if self.fdel is None:
raise AttributeError("can't delete attribute")
self.fdel(instance)
def getter(self, fget):
return type(self)(fget, self.fset, self.fdel)
def setter(self, fset):
return type(self)(self.fget, fset, self.fdel)
def deleter(self, fdel):
return type(self)(self.fget, self.fset, fdel)
2. 繼承與property
- 子類可重寫父類的 property:
class Parent: @property def value(self): return 10 class Child(Parent): @property def value(self): return 20
3. 性能考量
- 少量調(diào)用:
property的性能開銷極?。s 100ns / 次) - 大量調(diào)用:若性能敏感(如循環(huán)百萬次),建議直接訪問屬性
五、與其他技術(shù)的對(duì)比
| 技術(shù) | 用途 | 實(shí)現(xiàn)方式 |
|---|---|---|
| property | 屬性封裝與控制 | 裝飾器或 property () 函數(shù) |
| getter/setter | 傳統(tǒng)的訪問控制方法 | 顯式定義方法 |
| getattr | 動(dòng)態(tài)屬性獲取 | 魔法方法(所有屬性都經(jīng)過它) |
| setattr | 動(dòng)態(tài)屬性設(shè)置 | 魔法方法(所有屬性都經(jīng)過它) |
六、常見誤區(qū)與最佳實(shí)踐
1. 避免過度使用property
- 推薦場(chǎng)景:需要驗(yàn)證、計(jì)算或訪問控制的屬性
- 不推薦場(chǎng)景:簡單的數(shù)據(jù)封裝(直接使用公有屬性)
2. 私有屬性命名約定
- 使用單下劃線
_attr表示受保護(hù)屬性(非強(qiáng)制私有) - 使用雙下劃線
__attr進(jìn)行名稱修飾(Name Mangling)
3. 初始化時(shí)調(diào)用 setter
class Person:
def __init__(self, age):
self.age = age # 調(diào)用 setter 進(jìn)行驗(yàn)證
@property
def age(self):
return self._age
@age.setter
def age(self, value):
if value < 0:
raise ValueError("年齡不能為負(fù)數(shù)")
self._age = value
七、總結(jié)
| 場(chǎng)景 | 推薦實(shí)現(xiàn)方式 |
|---|---|
| 簡單屬性 | 直接使用公有屬性 |
| 需要類型檢查 / 驗(yàn)證 | 使用 property 裝飾器 |
| 只讀屬性 | 只實(shí)現(xiàn) getter 方法 |
| 計(jì)算屬性 | 使用 property 裝飾器 |
| 復(fù)雜的屬性訪問控制 | 自定義描述符類 |
合理使用 property 可以提高代碼的安全性、可維護(hù)性和可讀性,尤其在需要控制屬性訪問邏輯的場(chǎng)景中表現(xiàn)出色。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
python 彈窗提示警告框MessageBox的實(shí)例
今天小編就為大家分享一篇python 彈窗提示警告框MessageBox的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2019-06-06
詳細(xì)講解用Python發(fā)送SMTP郵件的教程
這篇文章主要詳細(xì)講解了用Python發(fā)送SMTP郵件的教程,包括在郵件中添加圖片等文件,強(qiáng)烈推薦!需要的朋友可以參考下2015-04-04
python-opencv中的cv2.inRange函數(shù)用法說明
這篇文章主要介紹了python-opencv中的cv2.inRange函數(shù)用法說明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2021-04-04
python自定義函數(shù)實(shí)現(xiàn)最大值的輸出方法
今天小編就為大家分享一篇python自定義函數(shù)實(shí)現(xiàn)最大值的輸出方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2019-07-07
盤點(diǎn)十個(gè)超級(jí)好用的高級(jí)Python腳本
這篇文章主要介紹了盤點(diǎn)十個(gè)超級(jí)好用的高級(jí)Python腳本,我們經(jīng)常會(huì)遇到一些大小問題,其中有很多的問題,都是可以使用一些簡單的Python代碼就能解決,需要的朋友可以參考下2023-04-04
Python時(shí)間序列數(shù)據(jù)的預(yù)處理方法總結(jié)
這篇文章主要介紹了Python時(shí)間序列數(shù)據(jù)的預(yù)處理方法總結(jié),時(shí)間序列數(shù)據(jù)隨處可見,要進(jìn)行時(shí)間序列分析,我們必須先對(duì)數(shù)據(jù)進(jìn)行預(yù)處理。時(shí)間序列預(yù)處理技術(shù)對(duì)數(shù)據(jù)建模的準(zhǔn)確性有重大影響2022-07-07

