1. 程式人生 > >guxh的python筆記:面向物件

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