@property裝飾器的簡單理解
python使用@property與__gertattr__創建動態類屬性
最近在讀mmdetection的源碼,發現其中有很多的property與__gertattr__的使用,這裡研究記錄一下這兩個方法的使用。
問題示例
一個例子的問題描述:對於一張影像:
-
屬性: 寬, 高
-
方法:翻轉,旋轉
class Image:
def __init__(self, width, height):
self.width = width
self.height = height
def flip(self):
pass
def rotate(self):
pass
如果需要添加一個屬性長寬比怎麼辦:
方法一、添加self.aspect_ratio屬性
最直接的方法,添加一個self.aspect_ratio屬性:
class Image:
def __init__(self, width, height):
self.width = width
self.height = height
self.aspect_ratio = self.height / self.width
def flip(self):
pass
def rotate(self):
pass
但是對於這個程式碼執行如下的操作就會出現問題,當修改影像的寬或者高以後,影像的寬高比就會出錯:
i = Image(1, 3)
print(i.width, i.height, i.aspect_ratio) # 1 3 3.0
i.width = 4
print(i.width, i.height, i.aspect_ratio) # 4 3 3.0
方法二、將寬高比定義為一個方法
另外一種正確的方法,將寬高比定義為一個方法:
class Image:
def __init__(self, width, height):
self.width = width
self.height = height
def flip(self):
pass
def rotate(self):
pass
def aspect_ratio(self):
return self.height / self.width
i = Image(1, 3)
print(i.width, i.height, i.aspect_ratio()) # 1 3 3.0
i.width = 4
print(i.width, i.height, i.aspect_ratio()) # 4 3 0.75
這種方法雖然得到的結果正確,但是不是一個真正的屬性方法。
方法三、 property裝飾器
使用@property裝飾器,神奇的將一個方法看起來像是一個屬性:
class Image:
def __init__(self, width, height):
self.width = width
self.height = height
# self.aspect_ratio = self.height / self.width
def flip(self):
pass
def rotate(self):
pass
@property
def aspect_ratio(self):
return self.height / self.width
i = Image(1, 3)
print(i.width, i.height, i.aspect_ratio) # 1 3 3.0
i.width = 4
print(i.width, i.height, i.aspect_ratio ) # 4 3 0.75
## 方法四、使用__gertattr__方法獲取屬性
class Image:
def __init__(self, width, height):
self.width = width
self.height = height
# self.aspect_ratio = self.height / self.width
def flip(self):
pass
def rotate(self):
pass
def __setattr__(self, name, value):
if name == 'aspect_ratio':
raise Exception('aspect_ratio can\'t be set. ')
else:
serlf.__dict__[name] = value
def __getattr__(self, name):
if name == 'aspect_ratio':
return self.height / self.width
else:
raise AttributeError
其他,gertattr函數的使用方法
getattr獲取屬性的值
class Image:
def __init__(self, width, height):
self.width = width
self.height = height
# self.aspect_ratio = self.height / self.width
def flip(self):
pass
def rotate(self):
pass
@property
def height2(self):
return getattr(self, 'height')
i = Image(1, 3)
print(i.width, i.height, i.height2) # 1 3 3
如果getattr的name在勒種不存在這樣的屬性,那麼將會報錯,可以設置為一個默認值。
class Image:
def __init__(self, width, height):
self.width = width
self.height = height
# self.aspect_ratio = self.height / self.width
def flip(self):
pass
def rotate(self):
pass
@property
def height2(self):
return getattr(self, 'height1', 0)
i = Image(1, 3)
print(i.width, i.height, i.height2) # 1 3 0
更多編程筆記文章: //github.com/lxztju/notes
