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筆記:類的屬性