Python進階(二)Python中的類繼承、封裝、多態使用方法

  python中可以在類的外面給對象增加屬性,比如tom.name="Tom"就可以給tom類增加一個name屬性,但是這種方法並不推薦使用,最好都封裝在類的內部。

  在類的內部封裝可以通過self實現,self的地址會跟實例化對象的地址一樣。

  在python3object是所有類的基類。

封裝

  所謂封裝,就是將屬性方法抽象地封裝到一個類中。

繼承和重寫

  面向對象(OOP)三要素(封裝 繼承 多態)之一,繼承Inheritance。繼承可以讓子類從父類獲取特徵(屬性和方法),在面向對象的世界中,從父類繼承,就可以直接擁有父類的屬性和方法。

  它可以使用現有類的所有功能,並在無需重新編寫原來的類的情況下對這些功能進行擴展,這樣可以減少代碼,多複用,子類可以定義自己的屬性和方法。

  在使用面向對象開發前,應該首先分析需求,確定一下,程序中需要包含哪些類。

繼承基本思想

  在使用類創建一個對象的時候就會執行init方法,如果子類實現了init方法,會走子類中的init方法,如果子類沒有實現init方法,會找繼承父類init方法。

class Envrioment:
    def __init__(self,env):
        self.env = env
    def get_observation(self):
        print("Get Observation")
class Big_Env(Envrioment):
        pass
a = Big_Env(1)
a.get_observation()
print(a.env)
>>>Get Observation
	1

  繼承是具有傳遞性的,也就是子類也會有爺爺類的方法。

super()擴展父類,重寫

  如果父類原本封裝的方法實現是子類方法的一部分,就可以使用擴展的方式。在需要的位置使用super().父類方法來調用父類方法的執行,代碼其它的位置針對子類的需求編寫子類特有的代碼實現。

  在pythonsuper()是一個特殊的類,super()就是使用super類創建出來的對象,最常使用的場景就是在重寫父類方法時,調用在父類中封裝的方法實現。

  子類同樣是不能訪問父類的私有屬性和私有方法的

  可依據魔法屬性mro(method resolution order)順序查看。

class little_animal():
    def __init__(self, sleep):
        self.sleep = sleep
class animal(little_animal):
    def __init__(self, sleep, eat, drink):
        super().__init__(sleep)
        self.eat = eat
        self.drink = drink
    def run(self):
        print("rrrrr")
class dog(animal):
    def __init__(self,bark,sleep,eat,drink):
        super().__init__(sleep,eat,drink)
        self.bark = bark
    def run(self):
        super().run()
        print("ttttt")
a = dog(1,2,3,4)
print(a.bark, a.sleep, a.eat, a.drink)
a.run()
print(dog.__mro__)

  輸出:

1 2 3 4
rrrrr
ttttt
(<class '__main__.dog'>, <class '__main__.animal'>, <class '__main__.little_animal'>, <class 'object'>)

  在繼承裏面一定要注意的是繼承不是複製,他只是指向父類,此時如果改變父類的值,子類相應的值也會發生改變。只有重寫之後,也就是在子類中對其進行重新賦值之後,改變父類的值不會改變子類的值。

多繼承

  子類可以有多個父類,並且具有所有父類的屬性和方法。

class A:
    def test(self):
        print("Test")
class B:
    def demo(self):
        print("demo")
class C(A,B):
    pass
C_test = C()
C_test.test()
C_test.demo()
>>>Test
   demo

  在多繼承中要注意的問題就是,應該儘量避免產生不同父類存在同名的方法

  爲了保證編寫的代碼能夠同時在Python2Python3中同時運行,今後定義類時,如果沒有父類,建議統一繼承自object

多態

  多態:不同的子類對象調用相同的父類方法,產生相同的執行結果。多態可以增加代碼的靈活度,以繼承和重寫父類方法爲前提。是調用方法的技巧,不會影響到類的內部設計。

class Dog(object):
    def __init__(self, name):
        self.name = name
    def paly(self):
        print("Dog {} Play With Game".format(self.name))
class Fly_Dog(object):
    def __init__(self, name):
        self.name = name
    def play(self):
        print("Fly_Dog {} Play With Game".format(self.name))
class Person(object):
    def __init__(self, name):
        self.name = name
    def play(self, dog):
        print("Person {} Play With Dog {}".format(self.name, dog.name))
P = Person("Bob")
P.play(Dog("Wangcai"))
P.play(Fly_Dog("xiaotian"))
>>> Person Bob Play With Dog Wangcai
	Person Bob Play With Dog xiaotian

類屬性

  使用面向對象開發,第一步是設計類。使用類名()創建對象,創建對象的動作有兩步:

  1. 在內存中爲對象分配空間。‘
  2. 調用初始化方法__init__爲對象初始化

  對象創建後,內存中就有一個對象的實實在在的內存(實例)。上述是創建對象的完整過程。

  1. 若創建了多個對象,每個對象有自己獨立的內存空間保存各自不同的屬性
  2. 多個對象的方法,在內存中只有一份需要把對象的引用傳遞到方法內部。

  在Python中類是一個特殊的對象,且一切皆對象。在程序運行時,類對象同樣會被加載到內存

  • class AAA:定義的類屬於類對象
  • obj1 = AAA(): 屬於實例對象

  在程序運行時,類對象在內存中只有一份,使用一個類可以創建很多個對象實例。除了封裝實例的屬性方法外,類對象還可以擁有自己的屬性方法

class Tool(object):
    count = 0
    def __init__(self):
        Tool.count += 1
a = Tool()
b = Tool()
print(Tool.count)
print(b.count)
>>> 2
	2

  類屬性用來記錄與這個類相關的特徵,不會記錄具體對象的特徵。如果通過實例化對象來訪問,其會先在實例化對象的方法中找該屬性,沒有的話就會在類裏面去找。因此訪問類屬性有兩種方式:

  1. 類名.類屬性
  2. 對象.類屬性(不推薦)

  如果這裏程序最後再設置b.count=10,那麼此時python解釋器會給實例化的對象b創建一個屬性,而不是向上去查找類屬性,因此不會改變Tool.count的值。也就是說使用對象.類屬性=值賦值語句,只會給對象添加一個屬性,而不會影響到類屬性的值

類方法

  從上文類屬性的文章中我們可以知道,使用賦值語句在class關鍵字下方可以定義類屬性。

  • 類方法就是針對類對象定義的方法。在類方法內部可以直接訪問類屬性,或者調用其他的類方法。

  語法如下:

@classmethod
def 類方法名(cls):
	pass

  類方法需要用修飾器@classmethod來標識,告訴解釋器這是一個類方法

  第一個參數cls。由哪一個類調用的方法,方法內的cls就是哪一個類的引用,這個參數和實例方法的第一個參數是self類似,使用其他名稱也可以,不過習慣使用cls

  通過類名.調用類方法調用方法時,不需要傳遞cls參數,在方法內部可以通過cls.訪問類的屬性,也可以通過cls.調用其他類方法。

class Tool(object):
    count = 0
    @classmethod
    def num_of_count(cls):
        print("The num of tool is {}".format(cls.count))
    def __init__(self):
        Tool.count += 1
a = Tool()
a.num_of_count()
>>> The num of tool is 1

靜態方法

  開始之前先總結一下類方法實例方法:1. 如果需要訪問實例屬性,那將這個方法封裝成實例方法。2. 如果某一個方法不需要訪問實例屬性,但是需要訪問類屬性,那麼這個時候可以考慮將這個方法封裝成類方法。

  如果某一個方法既不需要訪問其類屬性,也不需要訪問其實例屬性(裏面沒有用到self.這種操作訪問東西,比如單純的一個print),那麼可以將這個方法封裝成靜態方法

  語法如下:

@staticmethod
def 靜態方法(): # 不需要指定第一個參數,因爲它什麼都不需要訪問
	pass

  如:

class Dog(object):
    @staticmethod
    def run():
        print("Run ...")
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章