guxh的python筆記:面向對象
1,面向對象編程思想
類:一類具有相同屬性的抽象
屬性(靜態屬性):實例變量、類變量、私有屬性
方法(動態屬性):構造函數、析構函數(默認就有)、函數、私有函數
對象/實例:類經過實例化後,就是對象/實例
封裝 encapsulation:隱藏對象的屬性和實現細節,僅對外公開接口
繼承 inheritance:類派生子類
多態 polymorphism:一個接口,多種實現
舉例:
class Foo: # 類 typecode = ‘d‘ # 類變量 def __init__(self, x, y): # 構造函數 self.x = x # 屬性,實例變量 self._y = y # 私有屬性,實例變量 def _test(self): # 私有方法 return self.x def __del__(self): # 析構函數 pass f = Foo(1, 2) # 類的實例化 print(f) # 打印類的實例f
2,繼承
代碼重用
基類不應該被單獨實例化
2.1,繼承的方法
class Human: pass class Male(Human): pass
2.2,子類和父類重名的方法
直接寫會覆蓋,想保留父類方法可以先執行父類方法再增加子類方法。
class Human: def sleep(self): print(‘sleep 1s‘) class Male(Human): def sleep(self): super().sleep() # 執行父類方法一 Human.sleep(self) # 執行父類方法二 print(‘sleep 2s‘)
2.3,子類的構造函數
需要先覆蓋父類的構造函數,再繼承父類的屬性,再增加自己的屬性,父類:
class Human: def __init__(self, name): self.name = name
子類構造函數方法一,多重繼承時按指定父類繼承:
class Male(Human): def __init__(self, name, age): Human.__init__(self, name) self.age = age
子類構造函數方法二,多重繼承時按順序繼承:
class Male(Human): def __init__(self, name, age): super().__init__(name) self.age = age
2.3,多重繼承
classA
classB(A)
classC(A)
classD(B, C)
ABCD含有相同方法時:
廣度優先:先BC再A
深度優先:先BA再C
python3是廣度優先
3,多態
3.1,實現多態
在父類中的一個方法,輸入不同子類的對象時,可以實現不同的效果。
父類:
class Human: def __init__(self, name, age): self.name = name self.age = age
子類Male:
class Male(Human): def hobby(self): print(‘sports‘)
子類Female:
class Female(Human): def hobby(self): print(‘shopping‘)
不同子類,hobby輸出不同,實現了多態:
m = Male(‘m‘, 20) f = Female(‘f‘, 20) m.hobby() # sports f.hobby() # shopping
還可以編寫一個入口函數,統一輸出不同對象的hobby:
def get_hobby(obj): obj.hobby() get_hobby(m) # sports get_hobby(f) # shopping
3.2,通過抽象基類強制要求子類必須實現方法
如果想要求子類在繼承時必須實現hobby方法,可以對父類進行如下改造:
import abc class Human(abc.ABC): def __init__(self, name, age): self.name = name self.age = age @abc.abstractmethod def hobby(self): # 抽象方法無需實現,直接註釋或pass即可 """必須實現hobby"""
4,內置三大類裝飾器
4.1,@staticmethod
如果一個方法在類中定義,但沒有用到類中的實例屬性或者方法,建議加上staticmethod或者classmethod。
staticmethod:本質上就是放在類中的全局函數(可以通過類或實例調用),和類沒關系,完全可以放在類的外面。
class Foo: def __init__(self, x): self.x = x @staticmethod def run(): print(‘hello world‘) f = Foo(1) f.run() # 輸出hello world,通過類的實例調用 Foo.run() # 輸出hello world,通過類調用
4.2,@classmethod
和staticmethod的區別是可以調用類的屬性或方法。
被classmethod裝飾的函數第一個參數是類的引用,相當於類的實例中執行type(self),或者self.__class__。
class Foo: hw = ‘hello world‘ def __init__(self, x): self.x = x @classmethod def run(cls): print(cls.hw) f = Foo(1) f.run() # 輸出hello world,通過類的實例調用 Foo.run() # 輸出hello world,通過類調用
如果是實例想調用類的屬性或方法,可以通過如下方法:
class Foo: hw = ‘hello world‘ def __init__(self, x): self.x = x def run(self): print(type(self).hw) print(self.__class__.hw) f = Foo(1) f.run() # 輸出hello world,通過類的實例調用 Foo.run(f) # 由於沒有聲明classmethod,無法通過Foo類直接調用run,想調用需把實例f傳進去
4.3,@property
詳見guxh的python筆記:類的屬性
guxh的python筆記:面向對象