實際案例:
在面向對象編程中,我們把方法(函數)看作對象的接口,直接訪問對象的屬性可能是不安全的,或設計上不夠靈活。但是使用調用方法在形式上不如訪問屬性簡潔。
# 創建圓的類,獲得圓的半徑或設置圓的半徑,需要為這個類添加如下兩個方法
# 訪問器和設置器形式:
circle.getRadius()
circle.setRadius(5.0) # 繁
# 直接訪問形式:
circle.radius
circle.radius = 5.0 # 簡
能否在形式上是屬性訪問,但實際上調用方法?
解決方案:
使用property函數為類創建可以管理屬性(方法),fget/fset/fdel對應相應屬性訪問。
from math import pi
class Circle(object):
def __init__(self, radius):
# 圓半徑
self.radius = radius
def get_radius(self):
# 對半徑保留2位小數取四捨五入
return round(self.radius, 2)
def set_radius(self, value):
if not isinstance(value, (int, float)):
raise ValueError('wrong type')
self.radius = float(value)
def get_area(self):
# 獲得圓的面積
return self.radius ** 2 * pi
# 3個參數分別對應,訪問方法、設置方法、刪除方法
R = property(get_radius, set_radius)
c = Circle(3.2)
'''
安全性:
直接訪問屬性可能會存在問題,在某些時刻用戶參數值可能傳錯了,
傳了一個字符串,在邏輯上顯然已經錯誤了半徑不可能是字符串,
但是在程序運行上不會有任何錯誤。因為實例的屬性可以是任何類型。
用戶並不知道它的邏輯上出現錯誤,繼續做計算結果顯示是錯誤的。
'''
c.radius = 'abc'
d = c.radius * 2
print(d)
'''
邏輯上錯了但運行上沒有錯,這就導致程序出現一些莫名其妙問題。
希望能在賦值的這個點上就知道程序已經出錯了,這就是使用方法優勢,
使用方法的時候手段就變多了,可以對參數值進行類型檢查。
'''
# c.set_radius('abc')
c2 = Circle(3.2)
'''
靈活性:
開始的時候圓的半徑總是用戶輸出什麼就返回什麼,
後來需求改變了希望用戶看到的半徑是原來輸入的
保留兩位小數並且四捨五入結果。
這種情況下如果使用方法這種情況就很好解決,
這裡面涉及到一個隱藏,不想讓用戶看到真實的東西。
'''
# 用戶的radius沒有變但得到的結果改變了
print(c2.get_radius())
# 使用property函數安全簡潔高效調用各個方法
c3 = Circle(3.2)
# 會調用property第1個訪問方法get_area
print(c3.R)
# 賦值時候,會調用property第3個設置方法set_radius
c3.R = 5.9
print(c3.R)