Python物件導向三大特性

程式設計師小城發表於2019-03-17

Python是物件導向的語言,也支援物件導向程式設計的三大特性封裝(隱藏)、繼承、多型。

一、封裝(隱藏):

隱藏物件的屬性和實現細節,只對外提供必要的方法。相當於將"細節封裝起來",只對外暴露“相關呼叫方法”。通過私有屬性私有方法的方式實現封裝。Python追求簡潔的語法,沒有嚴格的語法級別的"訪問控制符",更多的是依靠程式設計師的自覺實現。

二、繼承:

如果一個新類繼承自一個設計好的類,就直接具備了已有類的特徵,就大大降低了工作難度,已有的類,我們稱為"父類或基類",新的類,我們稱為“子類或派生類”。

繼承可以讓子類具有父類的特性,提高了程式碼的重用性。

Python支援多重繼承一個子類可以繼承多個父類,繼承的語法格式如下:

class  子類類名(父類1,父類2,…):
    類體

如果在類定義中沒有指定父類,則預設父類是object類,也就是說object類是所有類的父類,因此所有類都有object類的屬性和方法,object類裡面定義了一些所有類共有的預設實現,比如__init()__,_new__()。

定義子類時,必須在其建構函式中呼叫父類的建構函式(此處只是邏輯上的必須,語法上沒有嚴格要求,但是一般要調),呼叫格式如下:

父類名.__init__(self,引數列表)

#測試繼承的基本使用
class Person:
    def __init__(self,name,age):  #屬性在構造器中
        self.name=name
        self.__age=age  #私有屬性(子類可以呼叫,但是不能用,也就是說子類繼承了父類所有的屬性方法,但是父類私有的屬性方法子類不能用)
    def say_age(self):
        print("嘿嘿,不告訴你")
class Student(Person):
    def __init__(self,name,age,score):
        Person.__init__(self,name,age)#必須顯式的呼叫父類初始化方法,不然直譯器不會去呼叫
        self.score=score
# Student——>Person——>object類
print(Student.mro())#檢視類的繼承層次結構
s=Student("張無忌","18","100")
s.say_age()
print(s.name)
# print(s.age)  父類的私有屬性,子類不能用
print(dir(s))
print(s._Person__age)#例項物件._類名__私有屬性  這樣才可以用(這說明Python中並沒有完全意義上的私有,需靠程式設計師的自覺性去維護)
如果在子類中需要父類的構造方法就需要顯式的呼叫父類的構造方法,或者重寫父類的構造方法。
如果子類不重寫 __init__,例項化子類時,會自動呼叫父類定義的 __init__
如果重寫了__init__ 時,例項化子類,就不會呼叫父類已經定義的 __init__
如果重寫了__init__ 時,要繼承父類的構造方法,可以使用 super 關鍵字

類成員的繼承和重寫:

1.成員繼承:子類繼承了父類除構造方法之外的所有成員。

2.方法重寫:子類可以重新定義父類中的方法,這樣就會覆蓋父類中的方法,也稱為重寫。

class Person:
    def __init__(self,name,age):
        self.name=name
        self.__age=age
    def say_age(self):
        print("我的年齡是",self.__age)
    def say_introduce(self):
        print("我的名字是{}".format(self.name))
class Student(Person):
    def __init__(self,name,age,score):
        Person.__init__(self,name,age)
        self.score=score
    def say_introduce(self):
        '''重寫了父類的方法'''
        print("報告老師,我的名字是{}".format(self.name))
s=Student("張無忌",18,100)
s.say_age()
s.say_introduce()

#列印結果
我的年齡是 18
報告老師,我的名字是張無忌

通過類的方法mro()或者類的屬性_mro_可以輸出這個類的繼承層次結構。

通過類的方法dir()檢視物件屬性

class A:
    pass
class B(A):
    pass
class C(B):
    pass
#mro()檢視類的繼承層次結構
print(C.mro())   #或者用 print(C.__mro__)
#dir()檢視物件屬性
a=A()
print(dir(a))

#結果如下:
[<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']

重寫_str_方法:

用於返回一個對於“物件的描述”,對應於內建函式str()經常用於print()方法,幫助我們檢視物件的資訊。_str_()可以重寫。

class Person():
    def __init__(self,name):
        self.name=name

p=Person("張三丰")
print(p)

#列印結果如下:  object類中__str__()的預設實現,列印類的資訊
<__main__.Person object at 0x03110D30>

_str_()重寫後

class Person():
    def __init__(self,name):
        self.name=name
    def __str__(self):
        return "名字是:{}".format(self.name)
p=Person("張三丰")
print(p)
#列印結果如下:
名字是:張三丰

關於多重繼承:

Python支援多重繼承,一個子類可以有多個“直接父類”,這樣就具備了多個父類的特點,但是由於這樣會把“類的整體層次”搞得很複雜,儘量避免使用

#測試多重繼承
class A:
    def aa(self):
        print("aa")
class B:
    def bb(self):
        print("bb")
class C(A,[B]):
    def cc(self):
        print("cc")

c=C()
#列印結果:
c.aa()
c.bb()
c.cc()

 

mro()

Python支援多繼承,如果父類中有相同名字的方法,在子類沒有指定父類名時,直譯器將“從左向右”按順序搜尋。

MRO(Method Resolution Order):方法解析順序,我們可以通過mro()方法獲得“類的層次結構”,方法解析順序也是按照這個“類的層次結構”尋找到。

class A:
    def aa(self):
        print("aa")
    def say(self):
        print("say AAA!")
class B:
    def bb(self):
        print("bb")
    def say(self):
        print("say BBB!")
class C(A,B):
    def cc(self):
        print("cc")

c=C()
print(C.mro())
c.say()  #直譯器尋找方法是"從左到右的順序"尋找,此時會執行A類中的say()
#列印結果
[<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>]
say AAA!

super()獲得父類定義

在子類中,如果想要獲得父類的方法時,我們可以通過super()來做,super()代表父類的定義,而不是父類物件。

#測試super()代表和父類有關,而不是父類物件!
class A:
    def say(self):
        print("A:",self)
class B(A):
    def say(self):
        # A.say(self) 也可呼叫
        super().say()  #()中沒有傳self說明呼叫的是類方法,()中傳self說明呼叫的是類的例項化方法
        print("B:",self)
B().say()

 

三、多型:

多型(polymorphism)是指同一個方法呼叫,由於物件不同可能會產生不同的行為。

注意:

1.多型是方法的多型,屬性沒有多型

2.多型的存在有兩個必要條件:繼承、方法重寫

 

class Man:
    def eat(self):
        print("餓了,吃飯了!")
class Chinese(Man):
    def eat(self):
        print("中國人用筷子吃飯")

class English(Man):
    def eat(self):
        print("英國人用刀叉吃飯")

class Indian(Man):
    def eat(self):
        print("印度人用右手吃飯")


def manEat(m):
    if isinstance(m,Man):
        m.eat()
    else:
        print("不能吃飯")

manEat(Chinese())
manEat(English())

#執行結果
中國人用筷子吃飯
英國人用刀叉吃飯

相關文章