1. 程式人生 > >guxh的python筆記:面向對象

guxh的python筆記:面向對象

調用 建議 -s ssa trac clas 默認 私有屬性 icm

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筆記:面向對象