今天我們要介紹一個比較進階的OOP在Pyhton裡面的操作:
我想這個更精確來說應該叫做屬性,其實現在來說Property(特性)和Attribute(屬性)已經被混用了!但在python中簡言之就是要找一個物件中另外一個物件或者實例,這時候會透過.
來幫忙,例如下面code中的self.grade
就是要在自身(self
,這裡就是class)裡面找到grade
這個屬性。
奇怪啦!這裡又跟dictionary有關係了?迷錯!python在物件裡預設有dict的屬性,直接存有每個屬性的資料,可以方便取用,然而可以發現A.__dict__
沒有出現bouns的資料,直到final_grade.__dict__
才列出bonus的資列,但看不到A.__dict__
的資料,但其實A.__dict__
是有存在final_grade.__dict__
,在輸出中已經有告訴之的位置。簡言之,Python在尋找物件屬性時,並不只針對物件本身,還會搜尋其類別的屬性,當然還是有例外,但大致上搜尋屬性的順序為:
from functools import reduce
class final_grade:
bonus=3
def __init__(self,name='name',gra='grade',HW=0,mid=0,final=0):
self.name=name
self.grade=gra
self.hw=HW
self.mid=mid
self.fin=final
def weight(self):
hw_w=0.25
mid_w=0.35
fin_w=0.4
return [hw_w,mid_w,fin_w]
def rank(self):
score=[self.hw,self.mid,self.fin]
we=self.weight()
return reduce(lambda a,b:a+b,map(lambda x,y:x*y,score,we))
A=final_grade('Jack','4',80,70,85)
print(A.rank())
#output:78.5
print(A.__dict__)
#output:{'name': 'Jack', 'grade': '4', 'hw': 80, 'mid': 70, 'fin': 85}
print(final_grade.__dict__)
#output:
#{'__module__': '__main__',
#'bonus': 3
#'__init__': <function final_grade.__init__ at memory>,
#'weight': <function final_grade.weight at memory>,...,
#'__dict__': <attribute '__dict__' of 'final_grade' objects>,
#'__weakref__': <attribute '__weakref__' of 'final_grade' objects>,
#'__doc__': None}
有時候為了避免在操作OOP時,讓外部的操作造成屬性被修改,會使用所謂的「封裝(Encapsulation)」這樣的方法。最簡單的方法即在原本的變數名稱上加上_
,例如將self.name
改成self._name
,此時其實是因為無法準確抓到名稱造成無法得到資料。在一般情況下,會用self.var1=var1
這類的命名方法,但其實是可以更改命名的,例如下方的self.fin
也可能得到類似加上_
的效果。
class final_grade:
def __init__(self,name='name',hw=0,final=0):
self._name=name
self.hw=hw
sele.fin=final
A=final_grade('Jack',80,70,85)
print('called A.__dict__:{}'.format(A.__dict__))
#output: called A.__dict__:{'_name': 'Jack', 'hw': 80, 'fin': 85}
print('called A._name:{}'.format(A._name))
#output: called A._name:Jack
print('called A.fin:{}'.format(A.fin))
#output: 'final_grade' object has no attribute 'name'
#print('called A.name:{}'.format(A.name))
#output: 'final_grade' object has no attribute 'final'
但有時候為了更改,但有要維持這時候我們會使用getter and setter
@property
來創造getter,此時,其下方函數就會立刻變成性質@name.setter
來暫時取代name
的特性class final_grade:
def __init__(self,name=None,final=0):
self.name=name
self.final=final
@property
def name(self):
return self._name
@name.setter
def name(self,name):
if
self._name=name
return
A=final_grade('Jack',85)
print('called A.name:{}'.format(A.name))
#output: called A.name:Jack
A.name='Eason'
print('called A.name:{}'.format(A.name))
#output: called A.name:Eason
raise
可以讓物件的操作更符合真正需求:class final_grade:
def __init__(self,name='name',final=0):
self.name=name
self.final=final
@property
def name(self):
return self._name
@name.setter
def name(self,name):
if name.isalpha():
self._name=name
else:
raise TypeError('driver need str.')
A=final_grade('Jack',85)
print('called A.name:{}'.format(A.name))
#output: called A.name:Jack
A.name='10'
print('called A.name:{}'.format(A.name))
#output: TypeError: driver need str.
好啦~今天就到這啦~