大家好,今天我要和大家分享的是物件導向-封裝
封裝的概念:
但其實沒有第二點也可以稱作封裝,第一點是最主要的概念,其實這個主要的概念我們在前幾日的範例也有用到哦,讓我們來看看:
class Person(object):
last_name = "Lin"
def __init__(self, name, height, weight, age):
self.name = name
self.height = height
self.weight = weight
self.age = age
@staticmethod
def tool():
status = "打開"
return "{status} 麥克風".format(status = status)
def introduce_myself(self):
print(id(self.name))
tool = Person.tool()
print("{tool} 説: 我叫 {name} 身高{height}cm 體重{weight}kg 年齡{age} years old".format(tool=tool, name=self.name, height=self.height, weight=self.weight, age=self.age))
if __name__ == '__main__':
Jacky = Person("Jacky", 180, 70, 18)
Jacky.introduce_myself() # 4514874120 & 打開 麥克風 説: 我叫 Jacky 身高180cm 體重70kg 年齡18 years old
Jacky.name = "Joke"
print(id(Jacky.name)) # 4514874344
Jacky.introduce_myself() # 4514874344 & 打開 麥克風 説: 我叫 Joke 身高180cm 體重70kg 年齡18 years old
這邊我建立一個實例叫Jacky(Instance)在Person(Class)底下,有著一些個人資料(Attribute),他有麥克風這個工具(staticmethod),而且會用來自我介紹(instance method),可以看到tool這個靜態方法,呼叫這個工具麥克風的時候有個狀態將開關打開,可是不用在意他怎麼打開的,在17行呼叫的時候就打開了,也就是說method的整個過程設計可以忽略,直接拿來就用,大概是這樣的意思。
這邊我在17、25行把各自的記憶位置印出,觀察使用公開屬性,我們可以發現一開始23行呼叫方法的self.name的記憶體位置,經過第24行的修改name屬性之後,再呼叫一次方法,可以發現裡面的self.name的記憶體位置,變成第24行我們修改name之後的記憶體位置。
接著再來是整個架構會用到一些資料,不論是屬性或者是方法,如果這些對你來說是非常重要的,不希望別人擅自更改,甚至更改之後會造成錯誤,像是我在24行,這個類別的外部去修改他的名字叫Joke,Jacky都不Jacky了,根本就是不同的結果,所以如果你想要對此做一個限制的話,你可以在屬性或者方法前面加上兩條底線,設定成私有屬性,這個私有屬性的意思就是不希望有人能夠從外部去存取或者是修改,改完的話會像是這樣:
class Person(object):
last_name = "Lin"
def __init__(self, name, height, weight, age):
self.__name = name
self.height = height
self.weight = weight
self.age = age
@staticmethod
def tool():
status = "打開"
return "{status} 麥克風".format(status = status)
def introduce_myself(self):
print(id(self.__name))
tool = Person.tool()
print("{tool} 説: 我叫 {name} 身高{height}cm 體重{weight}kg 年齡{age} years old".format(tool=tool, name=self.__name, height=self.height, weight=self.weight, age=self.age))
if __name__ == '__main__':
Jacky = Person("Jacky", 180, 70, 18)
Jacky.introduce_myself() # 4340163392 & 打開 麥克風 説: 我叫 Jacky 身高180cm 體重70kg 年齡18 years old
Jacky.__name = "Joke"
print(id(Jacky.__name)) # 4340163560
Jacky.introduce_myself() # 4340163392 & 打開 麥克風 説: 我叫 Jacky 身高180cm 體重70kg 年齡18 years old
如果有夥伴們發現記憶體每次位置每次都不一樣,那是正常現象哦~~ 重點在於修改屬性完的記憶體位置,有沒有被修改。
我在第6行改成使用私有屬性,正常來說應該是完全不能修改,但是在python中私有屬性,還是可以硬生生地去改,但是我們可以比照上面用公開屬性的結果可以發現,我們在使用私有屬性之後修改屬性,我們可以看見雖然24行一樣修改,可是我們原本的self.name沒有指向被修改後的記憶體位置,他還是原本的記憶體位置,沒有被修改,其實是因為在python裡面加上雙底線成為私有屬性的名稱,會經過名稱修飾變成另一個名稱,所以實際上如果要去修改私有屬性還是有辦法的,但是這裡並不建議這麼做。
如果要限制屬性不被修改,還有另一種方式「Property」屬性,也是我們在昨日有稍稍提到的,屬性的概念不變,只是使用Property能夠將讀取、修改、刪除寫成方法,這裡我把上面的例子修改了一下~
class Person(object):
last_name = "Lin"
def __init__(self, name, height, weight, age):
self.__name = name
self.height = height
self.weight = weight
self.age = age
@property
def name(self):
return self.__name
@staticmethod
def tool():
status = "打開"
return "{status} 麥克風".format(status = status)
def introduce_myself(self):
tool = Person.tool()
print("{tool} 説: 我叫 {name} 身高{height}cm 體重{weight}kg 年齡{age} years old".format(tool=tool, name=self.name, height=self.height, weight=self.weight, age=self.age))
if __name__ == '__main__':
Jacky = Person("Jacky", 180, 70, 18)
Jacky.introduce_myself() # 打開 麥克風 説: 我叫 Jacky 身高180cm 體重70kg 年齡18 years old
Jacky.name = "Joke" # AttributeError: can't set attribute
我新加上property在11-13行的地方,加上去我們可以從27行發現,如果想要對屬性做修改就會報錯,雖然我們的目的是想要阻止別人去修改他,如果這時候還想要修改這個屬性的話,我們可以使用有setter的修飾器,範例程式碼如下:
class Person(object):
last_name = "Lin"
def __init__(self, name, height, weight, age):
self.__name = name
self.height = height
self.weight = weight
self.age = age
@property
def name(self):
return self.__name
@name.setter
def name(self, name):
self.__name = "new_name " + name
@staticmethod
def tool():
status = "打開"
return "{status} 麥克風".format(status = status)
def introduce_myself(self):
tool = Person.tool()
print("{tool} 説: 我叫 {name} 身高{height}cm 體重{weight}kg 年齡{age} years old".format(tool=tool, name=self.name, height=self.height, weight=self.weight, age=self.age))
if __name__ == '__main__':
Jacky = Person("Jacky", 180, 70, 18)
Jacky.introduce_myself() # 打開 麥克風 説: 我叫 Jacky 身高180cm 體重70kg 年齡18 years old
Jacky.name = "Andy"
Jacky.introduce_myself() # 打開 麥克風 説: 我叫 new_name Andy 身高180cm 體重70kg 年齡18 years old
我在15-17行的部分加上了setter的修飾器,在經過31行之後就能夠順利的修改。
這裡做個簡單的小總結,封裝就是希望能夠將詳細的實作內容以及資訊隱藏,可以直接讓人呼叫方法馬上可以用,不用在意內部詳細的過程,在python我們也能透過私有屬性搭配property的使用,來達成這目標。
一個小概念分開來看似容易,當混在一起融會貫通時卻意外的複雜,物件導向的內容,大家在練習的時候也要多看幾篇文章以及官方文件,幫助自己釐清觀念,今天的內容就到這邊啦~~ 明天要來分享物件導向的繼承與多型。