Python OOP 面向對象編程

參考:黑馬程序員教程 - Python基礎 面向對象html

OOP三大特性,且三個特性是有順序的:python

  • 封裝
  • 繼承
  • 多態

封裝

指的就是把現實世界的事務,封裝、抽象成編程裏的對象,包括各類屬性和方法。
這個通常都很簡單,不須要多講。程序員

惟一要注意的就是:推薦從小往大開始封裝、開發類。好比 手槍,子彈這兩個類,咱們須要先定義和開發子彈的全部屬性和方法,而後再去開發上一層的手槍。這樣的話會很方便。反過來開發手槍的適合,發現寫到一半寫不下去要到子彈那裏寫,就很亂了。

繼承

子類能夠繼承父類和父父類的全部屬性、方法。編程

繼承格式:函數

class Parent:
    def func1(self):
        pass

class Son(Parent):
    def func2(self):
        func1()

方法改寫:
子類在不滿意時,也能夠進行本身的改寫父類的屬性、方法。
其中有兩種狀況:ui

  • Overwrite 覆蓋重寫父類方法:只須要寫一個同名函數便可覆蓋。
  • Extend 擴展父類函數:設計

    • 第一種方式(主要):寫一個同名函數,並在其中經過super().func()引用父類方法。其中super是一個python builtin 特殊類,而super()即生成一個super的實例。在子類中生成super實例,會獲得父類的引用。
    • 第二種方式(python 2.x之前使用):寫一個同名函數,再經過ParentName.func(self)引用父類方法。可是不推薦,由於父類名稱改變的話全部的子類都要改。

私有不繼承:
子類可以繼承的只是父類的公開內容,可是不包括父類的私有內容。
若是要訪問的話也能夠,可是須要間接的調用父類再用方法調用私有內容。code

多繼承

Python中,子類是能夠同時有多個父類的:也就是可以同時繼承多個父類的全部屬性、方法。htm

繼承格式:對象

class Father:
    def func1(self):
        pass

class Mother:
    def func2(self):
        pass

class Son(Father, Mother):
    def func3(self):
        func1()
        func2()

注意:
若是多個父類間存在有同名的方法,那麼會繼承第一個父類的方法。

MRO, Method Resolution Order

查看繼承順序:
經過類自帶的.__mro__屬性(MRO, Method Resolution Order),能夠查看這個類的繼承順序。

子類能夠直接寫FatherName.func()來調用父級函數。
可是當子類用super().func()時候,python就會根據MRO順序,由近到遠逐次尋找,找到最近的上級則返回。

用上例,若是是多繼承的話,那麼尋找順序是:SON -> Father -> Mother -> object

查看類的內置屬性和方法:

dir(className)能夠查看內置全部屬性方法。

Python內置的object基礎類

Python3開始使用新式的類定義,即默認讓全部定義的類都自動繼承一個叫object的內置基礎類。object基礎類定義了不少方便的屬性。包括18項之多。
而舊式的Python2.x時代,不繼承object基礎類,本身定義的類就只有__doc____module__兩樣內置屬性而已。2.x時代,若是須要手動繼承,如:

class MyClass(object):
    pass

多態

多態是指,不一樣的子類對象調用相同的父類方法,會產生多態多樣結果的編程特性。
多態的前提是可以繼承父類的方法,且可以重寫改寫父類的方法。

多態的特色:

  • 是調用方法的技巧,而不影響類的內部設計
  • 能夠增長代碼靈活度
def Father():
    def work(self):
        do_job()
     
    def do_job(self):
        print('Farming on the field...')


def Son(Father):
    def do_job(self):
        print('Programming at an office...')

# ---- Now let's work ----
Jason = Son()
Jason.work()

以上代碼中,一樣是work()函數,且要do_work()。可是,不一樣的人調用的是不一樣的do_work
Father調用本身的do_work,兒子由於本身重寫了do_work,因此調用本身的方法。
這就是多態——所繼承的方法,不須要再特殊指定誰用什麼方法,而對象會自動調用適合本身的方法。

類與實例

Python中,實例是一個對象,類也是一個對象,一切皆對象。但這也是Python OOP中引發不少麻煩的緣由。

實例對象很是好理解,也好用,直接用,就不說了。可是類對象就不那麼好理解了。

簡單說,類對象也是一個標準的對象,有本身的屬性和方法,只不過可以像模版同樣生成多個實例對象而已。
類對象有這兩大研究點:

  • 類屬性:就是能讓全部實例訪問和操做的公用廁所

    • 定義類屬性:位於class的全部方法以外
    • 訪問類屬性:className.propertyName
  • 類方法:比較難理解,必須用到名爲@classmethod的裝飾器,函數的第一個參數必須是關鍵字cls,如同self

    • @classmethod裝飾器:用來告訴解釋器這是一個類方法,而不是實例方法。
    • cls參數:

類屬性與實例屬性

這是Python OOP中困擾不少人的特色。可是其實不難理解,總結以下:

class MyClass:
    # 在這個位置定義的,叫類屬性。==等同於其它語言的「靜態屬性」
    # 這是每一個實例共有的公用屬性,至關於宿舍的公用洗澡間
    count = 0
    
    def __init__(self):
        # 用self.定義的,叫實例屬性,是每一個實例只本身全部的屬性,selfish
        self.name = "Jason"

訪問類屬性的方法有兩種:

  • ClassName.propertyName:推薦,直接用類名訪問類屬性。
  • Instance.propertyName:不推薦用實例名訪問類屬性,由於若是須要寫入操做,那麼這種方法只會給本身添加一個實例屬性,而不會影響類屬性。

動態添加類屬性

方法一:

>>> MyClass.newAttribute = 'I am a class attribute'
>>> print( MyClass.newAttribute )
'I am a class attribute'

方法二:裝飾器

# Customized decorator for classproperty
class classproperty(object):
    def __init__(self, getter):
        self.getter= getter
    def __get__(self, instance, owner):
        return self.getter(owner)

class MyClass:
    @classproperty
    def newAttribute(cls):
        return 'I am a class attribute.'

>>> print( MyClass.newAttribute )
'I am a class attribute'

之因此把方法封裝爲一個類屬性,是由於咱們有時候須要根據其它類屬性來定製這個類屬性。
而通常狀況下,咱們無法在類屬性定義的時候得到當前的類或類中其它的屬性。

類方法

類方法如同類屬性,是屬於全類的方法,可是(推薦)只用來訪問類屬性。

類方法:比較難理解,必須用到名爲@classmethod的裝飾器,函數的第一個參數必須是關鍵字cls,如同self

  • @classmethod裝飾器:用來告訴解釋器這是一個類方法,而不是實例方法。
  • cls參數:如同self,用來指代當前的類。

注意:@classmethodcls都是關鍵字,不能改。

代碼:

class MyClass:
    # 定義一個「類屬性」
    count = 0
    
    # 這裏開始定義「類方法」
    @classmethod
    def func(cls):
        print(cls.count)

類靜態方法

類中的staticmethod裝飾器一樣是python基礎類object的一個用於包裝、裝飾的方法。一旦在類方法前放上裝飾器@staticmethod,方法就會轉換爲一個靜態方法
靜態方法就是一個很是獨立的方法:既不訪問實例的信息,也不訪問類的信息。

代碼:

class MyClass:
    # 定義一個「類屬性」
    count = 0
    
    # 這裏開始定義「類方法」
    @staticmethod
    def func():
        pass

Property屬性

類中的property裝飾器,也是python基礎類object的一個用於包裝、裝飾的方法。一旦類方法前放上裝飾器@property,方法就會轉換爲一個類屬性。不少時候把方法假裝成屬性,是很是方便的。

class MyClass:
    # 這裏開始定義由方法轉換爲「類屬性」
    @property
    def name(self):
        return "Jason"

c = MyClass()
print( c.name )

在繼承object基礎類的狀況下,python給出了三種類屬性裝飾,對應三種操做:

  • 讀取:@property
  • 寫入:@name.setter
  • 刪除:@name.deleter

也就是說,當你讀取類屬性my_name的時候,會調用被@property修飾的方法;當你修改my_name當時候,會調用被@my_name.setter修飾的方法;當你刪除這個屬性時,會調用被@my_name.deleter修飾的方法。

注意:

  • 其中@property, @*.setter, @*.deleter,這是固定的名字,不能改。
  • 三種操做所修飾的三個函數,必須都是同一個名字:即「類屬性」名。

代碼:

class MyClass:
    # 這裏開始定義由方法轉換爲「類屬性」
    @property
    def name(self):
        return "Jason"

    @name.setter
    def name(self, value):
        self.name = value

    @name.deleter
    def name(self):
        del "Jason"

c = MyClass()

print( c.name )  # READ
c.name = "Brown"  # SET
del c.name  # DELETE

property屬性的應用

不少OOP語言,針對property屬性,通常操做是:一個私有屬性,配合兩個公有方法
如:

class MyClass:
    def __init__(self):
        self.__name = "Jason"

    def get_name(self):
        return self.__name

    def set_name(self, value):
        self.__name = value

c = MyClass()

# 開始調用
c.set_name("Brownee")
print( c.get_name() )

在Python下,能夠利用裝飾器改成如下代碼,極大方便調用的過程:

class MyClass:
    def __init__(self):
        self.__name = "Jason"

    @property
    def name(self):
        return self.__name

    @name.setter
    def name(self, value):
        self.__name = value

c = MyClass()

# 開始調用
c.name = "Brownee"
print( c.name )
相關文章
相關標籤/搜索