Python 類2
前言
考慮到有這幾天更新的內(nèi)容好像容量有點(diǎn)大.如果是跟著一路看過來的同學(xué),可能會(huì)感覺到比較吃力,打算將內(nèi)容講解的更細(xì)致點(diǎn),容量上更少點(diǎn)
前情提要
內(nèi)容提要
@property 裝飾的只讀屬性
@setter 裝飾的寫檢驗(yàn)屬性
內(nèi)容詳情
property
將一個(gè)類的方法用@property來裝飾一下,就變成了一個(gè)只讀的屬性
示例:只讀屬性
class MyClass(object):
'''類的說明文檔'''
def __init__(self):
self._name = ""
self._age = 0
# 定義一個(gè)用裝飾器裝飾的只讀屬性
@property
def age(self):
return 10
mc1 = MyClass()
print(mc1.age)
運(yùn)行效果
代碼解析:
def age(self):
return 10
這個(gè)東西,看上去像一個(gè)方法
但是因?yàn)橛? @property 裝飾 就變成了一個(gè)只讀屬性
@property
def age(self):
return 10
因此,在使用的時(shí)候,只需要用方法名(不要加括號(hào))就可以使用
mc1.age
如果嘗試修改這個(gè)屬性:
示例:嘗試修改只讀屬性
class MyClass(object):
'''類的說明文檔'''
def __init__(self):
self._name = ""
self._age = 0
@property
def age(self):
return 10
mc1 = MyClass()
print(mc1.age)
mc1.age = 100
運(yùn)行效果
這里特意用了只讀屬性來解釋這個(gè)用法,就是想要將它的主要功能之一給說明一下.
那還有什么功能呢?
可以對(duì)屬性做一些必要的計(jì)算
比如,我們?cè)O(shè)計(jì)了一個(gè)叫圓的類
屬性有圓心,半徑
這個(gè)時(shí)候,如果我們想要一個(gè)圓的周長(zhǎng)或者面積
如果用原來的方法,就需要再增加一個(gè)圓的周長(zhǎng)屬性或面積屬性.并且,當(dāng)我們改變圓的半徑的時(shí)候,這兩個(gè)屬性還不會(huì)跟著變,要手動(dòng)更新.
而有了這種方法定義的屬性,就可以實(shí)現(xiàn)計(jì)算聯(lián)動(dòng)效果
示例:只讀屬性的計(jì)算聯(lián)動(dòng)效果
class MyCircle(object):
def __init__(self, radius):
self.radius = radius
@property
def perimeter(self):
return 2 * 3.14 * self.radius
mc2 = MyCircle(10)
print(mc2.perimeter)
mc2.radius = 20
print(mc2.perimeter)
運(yùn)行效果
可以看到,當(dāng)我們改變了圓的半徑后,圓的直徑也跟著發(fā)生了改變.
而這種能力,用普通的屬性就很難實(shí)現(xiàn)
那我們即想實(shí)現(xiàn)這種效果,又想這個(gè)屬性是可寫的怎么辦?能不能辦到?
當(dāng)然可以,這個(gè)時(shí)候,我們就要用到另一個(gè)裝飾器@setter了
@setter
這個(gè)裝飾器的作用就是將只讀屬性,變成可寫屬性.
那么問題來了,即可讀又可寫,那它與普通屬性的意義何在呢?
示例:setter裝飾器的意義
class MyCircle2(object):
def __init__(self):
self.__radius = 0
@property
def radius(self):
return self.__radius
@radius.setter
def radius(self, radius):
if isinstance(radius, int) or isinstance(radius, float):
self.__radius = radius
else:
print("請(qǐng)輸入半徑的正確類型")
mc3 = MyCircle2()
# 正確的半徑
mc3.radius = 10
print(mc3.radius)
# 錯(cuò)誤的半徑值
mc3.radius = "1"
print(mc3.radius)
運(yùn)行效果:
代碼解析:
首先我們定義了一個(gè)用裝飾器裝飾的radius屬性
@property
def radius(self):
return self.__radius
至于返回值這么奇怪,我們先不用理會(huì).可以看到,我們就是定義了一個(gè)只讀屬性radius
然后,我們用setter裝飾器將這個(gè)屬性變成可寫的
setter的用法注意點(diǎn):
- @屬性名.setter
- 屬性名與@property 定義的屬性名必須一樣
如果不一樣,在調(diào)用的時(shí)候就會(huì)報(bào)錯(cuò)
示例:setter裝飾器的屬性名與property的屬性名不一樣
class MyCircle2(object):
def __init__(self):
self.__radius = 0
@property
def radius(self):
return self.__radius
@radius.setter
def radius2(self, radius):
if isinstance(radius, int) or isinstance(radius, float):
self.__radius = radius
else:
print("請(qǐng)輸入半徑的正確類型")
mc3 = MyCircle2()
# 正確的半徑
mc3.radius = 10
print(mc3.radius)
# 錯(cuò)誤的半徑值
mc3.radius2 = "1"
print(mc3.radius)
運(yùn)行效果
可以看到在調(diào)用時(shí)會(huì)報(bào)錯(cuò)
在正確的示例代碼中setter裝飾器裝飾的屬性代碼如下:
if isinstance(radius, int) or isinstance(radius, float):
self.__radius = radius
else:
print("請(qǐng)輸入半徑的正確類型")
可以看到,在我們賦值的時(shí)候,除了直接改變之外,我們還加一個(gè)條件判斷
用來判斷輸入的值是不是數(shù)值型的,
當(dāng)然,你還可以更加嚴(yán)格的判斷值是不是>0的
也就是,用這種方法改寫的可寫屬性,比直接設(shè)置的屬性更有效的地方在于,我們可以對(duì)所賦的值一個(gè)計(jì)算,檢驗(yàn)的效果,即進(jìn)行一個(gè)錯(cuò)誤預(yù)判處理機(jī)制.
總結(jié)
@property 裝飾的只讀屬性
- 在要轉(zhuǎn)化為屬性的方法前使用
- 將方法轉(zhuǎn)化為屬性使用邏輯
- 參數(shù)只能有一個(gè)self
- 如果只定義@property則屬性將只讀的
- 如果只定義@property的意義是將該屬性定義成可以與其他屬性聯(lián)動(dòng)效果的屬性.
@setter 裝飾的寫檢驗(yàn)屬性
- 要用@屬性名.setter
- 方法名必須與@property定義的屬性名一樣
- 參數(shù)除了self, 還必須有且只有一個(gè)參數(shù),可以是不定長(zhǎng)參數(shù)
- 定義@setter 的主要意義在于對(duì)屬性賦值時(shí),可以進(jìn)行一個(gè)額外的處理