iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 28
1
Software Development

從0開始學習程式-Python系列 第 29

[Day32] 物件不但是dict還可以封裝?

  • 分享至 

  • xImage
  •  

今天我們要介紹一個比較進階的OOP在Pyhton裡面的操作:

Attribute

我想這個更精確來說應該叫做屬性,其實現在來說Property(特性)和Attribute(屬性)已經被混用了!但在python中簡言之就是要找一個物件中另外一個物件或者實例,這時候會透過.來幫忙,例如下面code中的self.grade就是要在自身(self,這裡就是class)裡面找到grade這個屬性。

dict

奇怪啦!這裡又跟dictionary有關係了?迷錯!python在物件裡預設有dict的屬性,直接存有每個屬性的資料,可以方便取用,然而可以發現A.__dict__沒有出現bouns的資料,直到final_grade.__dict__才列出bonus的資列,但看不到A.__dict__的資料,但其實A.__dict__是有存在final_grade.__dict__,在輸出中已經有告訴之的位置。簡言之,Python在尋找物件屬性時,並不只針對物件本身,還會搜尋其類別的屬性,當然還是有例外,但大致上搜尋屬性的順序為:

  • 物件自己本身屬性
  • class的屬性
  • class's father或者更往前一代的屬性
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

但有時候為了更改,但有要維持這時候我們會使用getter and setter

  1. 利用@property來創造getter,此時,其下方函數就會立刻變成性質
  2. 透過@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.

好啦~今天就到這啦~


上一篇
[Day31] dict也可以排序嗎?
下一篇
[Day33] python的super繼承
系列文
從0開始學習程式-Python32
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言