此为历史版本和 IPFS 入口查阅区,回到作品页
為自己Coding
IPFS 指纹 这是什么

作品指纹

給自己的Python小筆記: Class 設計(下)

為自己Coding
·
·

Github連結

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

CC BY-NC-ND 2.0 授权