給自己的Python小筆記: Class 設計(下)
6. Static Method, Class Method, Abstract Method
1.簡單來說:
Static 與 Class 都可以當成是存取類別屬性的方法,他們不需要建立實體物件(instance),也就是前面章節提到的實體屬性,它就使用, 那他們有什麼差異呢,class 需要多帶一個cls的參數才能使用,而static不用
2. 簡單比較一下:
a. Static Method: 靜態的方法,不需要建立instance,也不需要帶一個cls當參數
b. Class Method: 類方法,不需要建立instance,需要帶一個cls當參數
c. Abstract Method: 抽象方法,還沒被實際create出來,它繼承class(類),要用覆寫的方式來實作
3.Static 與 Class : 我這邊實作一個同時包含class與static方法,他們做的事情一模一樣,只是一個讓類別屬性加1,另一個加2,可以從這邊看出都是要改變類別屬性的值,兩者的時作方法差異
a. Static Method: 在funtion前面加上@staticmethod
b. Class Method: 在function前面加上@classmethod,並且帶入一個參數cls
class House: tv_amount = 1 #類別屬性 def __init__(self, human, name): self.human = human ##實體屬性 self.name = name ##實體屬性 House.add_tv(1) ## static House.add_tv1(2) ## class @staticmethod def add_tv(i): House.tv_amount += i @classmethod def add_tv1(cls,i): cls.tv_amount += i little_turtle_home = House(1, "Turtle") print(little_turtle_home.name) # Turtle print(little_turtle_home.human) #1 print(little_turtle_home.tv_amount) #4 print(House.tv_amount)# 4 little_turtle_home1 = House(1, "Turtle") print(little_turtle_home1.tv_amount) #7 print(House.tv_amount) #7
4. Abstract Method: 就跟它的名字一樣,它是一個抽象的類,很抽象所以不能實例化(instance),它只能被子類別繼承
a. 首先我們先導入一個package: impot abc,很特別的名字
b. 再來,在我們想要抽象化的類裡面的參數,寫入abc.ABC 或 metaclass = abc.ABCMeta,就將它抽象化了
c. 抽象類裡面的function必須前面加上@abc.abstractmethod
d. 欲繼承的子類別,要在類參數裡寫入父類別的名稱
e. 記得: 繼承這個抽象類的子類別,必須有抽象類裡面的function,不然會出現錯誤,這個時候你就要再將這些function補上
我這邊就來實作一個抽象老烏龜,被兩隻小烏龜繼承,一隻有繼承swim,一隻沒有,結果沒有的就印不出來,原因就是沒有繼承父類別(抽象類別)的function
## import abstract package import abc class old_Turtle(abc.ABC): @abc.abstractmethod def swim(self): print('I can swim') return NotImplemented class young_turtle(old_Turtle): def swim(self): print('I can swim fast') def eat(self): print('I can eat') class little_turtle(old_Turtle): def eat(self): print('I can eat') print(young_turtle().swim()) # I can swim fast print(young_turtle().eat()) # I can eat print(little_turtle().eat()) # TypeError: Can't instantiate abstract class little_turtle with abstract methods swim
7. 類別 封裝(Encapsulation)
1. 目的: 很簡單,就是過往我們在Class裡面的屬性都是門戶洞開的,任何人都能輕易看到裡面的內容,但是我們有時候想要一點隱私(private),就是不想被別人輕鬆看見,所以我們要用封裝的方法,將屬性隱藏起來,但我們自己要讀,所以我們要用別的方式讀取這些屬性內容
2. 怎麼做: 我們只要將想要隱藏的屬性是別字加上__(兩個底線)就能輕鬆實現
舉例:
class House: def __init__(self, address, name, phone_number): self.__address = address self.__name = name self.phone_number = phone_number self.member = 0 little_turtle_home = House('any Town any Street', 'Turtle', '09xx') print(little_turtle_home.phone_number) ## 沒封裝: 09xx print(little_turtle_home.__address) ## 有封裝: AttributeError: 'House' object has no attribute 'address'
看不到了!!
3. 但是我們總是要自己看吧,所以要在function寫一個能獲取這個attribute(屬性)的方法
舉例:
class House: def __init__(self, address, name, phone_number): self.__address = address self.__name = name self.phone_number = phone_number self.member = 0 def get_attribute(self): return self.__address little_turtle_home = House('any Town any Street', 'Turtle', '09xx') print(little_turtle_home.phone_number) ## 沒封裝: 09xx # print(little_turtle_home.address) ## 有封裝: AttributeError: 'House' object has no attribute 'address' print(little_turtle_home.get_attribute()) ## 有封裝,但換個方法get起來 : any Town any Street
8. Class 中 再定義一個Class
這邊我們來看看一個特別的情況,在Class中再定義一個Class, 我們先定義一個Class(House),並在裡面再建立另一個Class(material),這邊先建立一個little_turtle_home(),接著建立一個新家new_little_turtle_home使用brick(new_little_turtle_home = little_turtle_home.material(“brick”)),當我們的material(class)
從範例中,可以看到我們定義了另一個class來存放material資訊,然後我們來看看如何使用這個新的Class
## 建立一個 Class class House: def __init__(self, address, name, phone_number): self.address = address self.name = name self.phone_number = phone_number ## 再建立一個class class material: def __init__(self, material): self.material = material def find(self): return "find out material!!" ## 先建立一個little_turtle_home little_turtle_home = House('any Town any Street', 'Turtle', '09xx') ## 再建立一個在little_turtle_home底下的class new_little_turtle_home = little_turtle_home.material("brick") ## 使用這個class的function print(new_little_turtle_home.find()) #find out material!! ## 查看House class 底下的資訊 print(little_turtle_home.address , little_turtle_home.name, little_turtle_home.phone_number, end=' ') # any Town any Street Turtle 09xx ## 在House底下建立個另一個class material ,沒辦法用它查看外層class House的資訊 # print(new_little_turtle_home.address , new_little_turtle_home.name, new_little_turtle_home.phone_number) # 'material' object has no attribute 'address' ## 使用這個class的屬性 print(new_little_turtle_home.material) # brick ## 查看原本建立的class little_turtle_home 底下的class material print(little_turtle_home.material) # <class '__main__.House.material'>
9. 新增參數 與 __slots__(不給新增參數) 用法
a. 我們可以透過.來直接賦予新的參數值給類(Class), 格式: (class).(variable name) = ‘(new value)’,Little_turtle_home.name = ‘Turtle’
b. pass: 順便一提,它是為了維持結構的完整性
class House(object): pass Little_turtle_home = House() Little_turtle_home.name = 'Turtle' ## 賦予新值 print(Little_turtle_home.name) #Turtle
c. __slot__ : 在Class中,寫下這個時,會沒辦法賦值,只有__slot__ = {},dict裡面的可以賦予值
舉例: 如果跟剛剛一樣賦予一個值給name,Little_turtle_home1.name = ‘Turtle’,這邊就會報錯,但是如果你賦予的值是__slot__ = {}裡面有的,就可以執行,Little_turtle_home1.phone = ‘09xx’
class House(object): pass Little_turtle_home = House() Little_turtle_home.name = 'Turtle' ## 賦予新值 print(Little_turtle_home.name) #Turtle class House1(object): __slots__ = {'people_amount','phone'} pass Little_turtle_home1 = House1() # Little_turtle_home1.name = 'Turtle' # 'House1' object has no attribute 'name' Little_turtle_home1.people_amount = 1 print(Little_turtle_home1.people_amount) #1 Little_turtle_home1.phone = '09xx' print(Little_turtle_home1.phone) #09xx
希望對您有幫助!!
Reference:
https://blog.louie.lu/2017/07/28/你所不知道的-python-標準函式庫用法-03-abc/
https://www.maxlist.xyz/2019/12/08/python-class-static-abstract-method/
https://chenhh.gitbooks.io/parallel_processing/cython/python_class.html
喜欢我的作品吗?别忘了给予支持与赞赏,让我知道在创作的路上有你陪伴,一起延续这份热忱!
- 来自作者
- 相关推荐