Python: 學習系列之五:類、繼承、多態、封裝

class A(object):
    # 類屬性
    name = 'cong'

    # 類方法
    @classmethod
    def cm(cls, p1):
        print(p1)

    # 構造函數
    def __init__(self, n):
        # 定義實例對象屬性並賦值
        self.age = 20
        # 定義實例對象的私有屬性,雙下劃線開頭表示私有訪問,外部訪問不到
        self.__city = 'shanghai'
        A.name = n  # 給類對象屬性賦值

    # 靜態方法
    @staticmethod
    def sm(p1, p2):
        print(p1, p2)

    # 實例方法
    def do_something(self):
        print('hello')

    # 定義實例對象的私有方法,雙下劃線開頭表示私有訪問,外部訪問不到
    def __set_city(self, city):
        self.__city = city

    # 對屬性進行的封裝
    def get_city(self):
        print('he is from %s' % self.__city)


a = A('congcong')
print(A.name)  # cong,使用類對象調用
print(a.name)  # cong,當使用實例去調的時候,實際指向類對象的引用
print(a.age)  # 20

A.cm('a')  # 類對象調用類方法
a.cm('a')  # 實例對象調用類方法

A.sm('a', 'b')  # 類對象調用靜態方法
a.sm('a', 'b')  # 實例對象調用靜態方法

a.do_something()  # 使用實例去調用函數

# ---------------在外部設置新的屬性-------------------------
A.sex = 'Male'  # 在類的外部定義新的類屬性
a.birthday = '2019-6-16'  # 在類的外部定義新的實例屬性

print(A.sex)
print(a.sex)
print(a.birthday)


# ---------------在外部設置新的方法-------------------------
# 在外部,定義一個函數作爲實例方法
def newF1(self):
    print('this is external method 1')


# 第一種方法,給類對象設置此實例方法
A.newF1 = newF1
a.newF1()

# 第二種方法,行不通,給實例對象設置此實例方法
# a.newF1 = newF1 # 不能這樣設置,會報TypeError: newF1() missing 1 required positional argument: 'self'

# 第三種辦法,動態綁定實例方法
from types import MethodType

a.newF1 = MethodType(newF1, a)
a.newF1()

繼承、重寫,MRO

"""
    Python所有的類都繼承一個統一的基類object
    Python子類可以繼承多個父類,這是與JAVA/C# 最大的不同,子類會繼續所有直接父類和間接父類的所有方法和屬性,包括類方法,靜態方法等
    如果兩個父類中有兩個相同的方法,Python是通過MRO(Method Resolution Order方法解析順序)來解決的
"""


# A是根父類
class A(object):
    def f(self):
        print('A.f')


# B繼承於A
class B(A):
    # 如果對繼承於父類的訪問不滿意,可以對此方法進行重寫,重寫的方式是:在子類中定義與父類中同名的屬性或方法(包括裝飾器)
    def f(self):
        print('B.f')


# C繼承於A
class C(A):
    def f(self):
        print('C.f')


# D繼承於兩個父類B和C
class D(B, C):
    def f(self):
        # 可以通過super()來調用父類的方法
        super().f()  # B.f
        super(D, self).f()  # B.f, super的第一個參數是類對象,第二個參數是實例對象
        # 根據D的MRO順序是D->B->C->A,那如果想改這個順序呢
        super(B, self).f()  # C.f, 以B的下一個類對象作爲被指定的父類
        super(C, self).f()  # A.f


d = D()
d.f()  # B.f 如果兩個父類中有兩個相同的方法,Python是通過MRO來解決的

# 通過調用類對象上的mro()方法,可以查看到解析順序
# [<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
print(D.mro())

多態

"""
    多態性意味着有多重形式。在面向對象編程範式中,多態性往往表現爲"一個接口,多個功能"
    具體主要使用方法是在父類中定義了一個方法,在不同的子類中對此方法進行重寫,在運行過程中根據變量所引用對象的類型,動態地決定調用哪個對象中的方法

"""


class ParentClass(object):
    def f(self):
        print('ParentClass.f')


class ChildClass1(ParentClass):
    def f(self):
        print('ChildClass1.f')


class ChildClass2(ParentClass):
    def f(self):
        print('ChildClass2.f')


def exec(obj):
    obj.f()


"""
    在JAVA/C#中,調用於必須用
    ParentClass p = new ParentClass(); p.f();
    ParentClass p = new ChildClass1(); p.f();
    ParentClass p = new ChildClass2(); p.f();
    這種方法來明確指定p的類型後,才能調用f方法,但在Python中不必要這樣
    Python是動態語言,它崇尚"鴨子類型":當看到一隻鳥走起來像鴨子,游泳起來像鴨子,叫起來像鴨子,那這隻鳥就是鴨子,而在JAVA/C#中必須先明確知道對象的類型是什麼,然後纔會執行對應的方法
    在鴨子類型中,我們並不關心對象的類型是什麼,到底是不是鴨子,只關心對象的行爲,代碼如下

"""
a = ParentClass()
exec(a)  # ParentClass.f
a = ChildClass1()
exec(a)  # ChildClass1.f
a = ChildClass2()
exec(a)  # ChildClass2.f

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章