首頁 > 軟體

Python基礎之物件導向進階詳解

2022-02-13 13:00:17

物件導向三大特徵介紹

封裝(隱藏):隱藏物件的屬性和實現細節,知對外提供必要的方法。

繼承:讓子類擁有父類別特徵,提高了程式碼的重用性。從設計上是一種增量進化,原有父類別設計不變的情況下,可以增加新的功能,或者改進 已有的演演算法

多型:一個方法呼叫由於物件不同會產生不同的行為。

繼承

繼承是程式碼複用的一個非常重要的手段,已有的類,我們稱為“父類別或者基礎類別”,新的類,我們稱為“子類或者派生類”。

語法格式

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

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

如果在類定義中沒有指定父類別,則預設父類別是 object 類。也就是說,object 是所有類的父 類,裡面定義了一些所有類共有的預設實現,比如:new()。

定義子類時必須在其建構函式中呼叫父類別的建構函式。呼叫格式如下:

父類別名.init(self, 參數列)

# 測試繼承的基本使用
class Person():
    def __init__(self, name, age):
        self.name = name
        self.__age = age #私有屬性
    def print_name(self):
        print(self.name)
class Student(Person):
    def __init__(self, name, age, id):
        Person.__init__(self, name, age)
        self.id = id
stu = Student('sherry',24,'2017')
stu.print_name()
print(Student.mro()) #檢視類的繼承層次結構
print(dir(stu))  # 列印所有方法和屬性
print(stu._Person__age) #繼承於父類別的私有屬性的存取
輸出:
sherry
[<class '__main__.Student'>, <class '__main__.Person'>, <class 'object'>]
['_Person__age', '__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__', 'id', 'name', 'print_name']
24

1.類成員的繼承和重寫 成員繼承:子類繼承了父類別除構造方法之外的所有成員,包括方法,屬性,私有方法,私有屬性,只不過私有方法和屬性不能直接存取。

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

# 重寫父類別方法的測試
class Person():
    def __init__(self, name, age):
        self.name = name
        self.__age = age #私有屬性
    def print_name(self):
        print(self.name)
class Student(Person):
    def __init__(self, name, age, id):
        Person.__init__(self, name, age)
        self.id = id
    def print_name(self):
        '''重寫了父類別的方法'''
        print('my name is ', self.name)
stu = Student('sherry',24,'2017')
stu.print_name()
輸出:
my name is  sherry

檢視類的繼承層次結構

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

class Person():
    def __init__(self, name, age):
        self.name = name
        self.__age = age #私有屬性
    def print_name(self):
        print(self.name)
class Student(Person):
    def __init__(self, name, age, id):
        Person.__init__(self, name, age)
        self.id = id
    def print_name(self):
        '''重寫了父類別的方法'''
        print('my name is ', self.name)
# stu = Student('sherry',24,'2017')
print(Student.mro())
輸出:
[<class '__main__.Student'>, <class '__main__.Person'>, <class 'object'>]

object根類

object 類是所有類的父類別,因此所有的類都有 object 類的屬性和方法。

dir()檢視物件屬性

# 測試繼承的基本使用
class Person():
    def __init__(self, name, age):
        self.name = name
        self.__age = age #私有屬性
    def print_name(self):
        print(self.name)
class Student(Person):
    def __init__(self, name, age, id):
        Person.__init__(self, name, age)
        self.id = id
    def print_name(self):
        '''重寫了父類別的方法'''
        print('my name is ', self.name)
obj = object()
stu = Student('sherry',24,'2017')
print(dir(obj))
print(dir(stu))
輸出:
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']
['_Person__age', '__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__', 'id', 'name', 'print_name']

str()方法的重寫

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

class Person():
    def __init__(self, name, age):
        self.name = name
        self.__age = age #私有屬性
    def print_name(self):
        print(self.name)
    def __str__(self):
        return 'name:{0} age:{1}'.format(self.name, self.__age)
p = Person('sherry', 24)
print(p)
輸出:
name:sherry age:24

多重繼承

Python 支援多重繼承,一個子類可以有多個“直接父類別”。這樣,就具備了“多個父 類”的特點。但是由於,這樣會被“類的整體層次”搞的異常複雜,儘量避免使用。(java不支援多重繼承)

class A():
    pass
class B():
    pass
class C(A,B):
    pass
print(C.mro())
輸出:
[<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>]

MRO()

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

class A():
    pass
class B():
    pass
class C(A,B):
    pass
print(C.mro())
輸出:
[<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>]

super()獲得父類別定義

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

# 測試super()
class A():
    def say(self):
        print('aa')
class B(A):
    def say(self):
        super().say()  #呼叫父類別方法
        A.say(self)		#呼叫父類別方法
        print('bb')
b = B()
b.say()
輸出:
aa
aa
bb

多型

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

關於多型要注意以下 2 點:

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

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

# 多型
class Man():
    def eat(self):
        print('eat!')
class Chinese(Man):
    def eat(self):
        print('eat with chopsticks')
class English(Man):
    def eat(self):
        print('eat with fork')
class Indian(Man):
    def eat(self):
        print('eat with hand')
def manEat(m):
    if isinstance(m,Man):
        m.eat()
    else:
        print('can not eat!') 
manEat(Man())
manEat(Chinese())
manEat(English())
manEat(Indian())     
輸出:
eat!
eat with chopsticks
eat with fork
eat with hand

特殊方法和過載運運算元

python重的運運算元實際上是通過呼叫物件的特殊方法實現的。

a = 20
b = 30
print(a+b)
print(a.__add__(b))
輸出:
50
50

常見的特殊方法:

每個運運算元實際上都對應了相應的方法:

# 測試運運算元過載
class Person():
    def __init__(self, name):
        self.name = name
    def __add__(self, other):
        if isinstance(other, Person):
            return '{0}-{1}'.format(self.name, other.name)
    def __mul__(self, other):
        if isinstance(other, int):
            return self.name * other
p1 = Person('Sherry')
p2 = Person('Lily')
print(p1 + p2)
print(p1*10)
輸出:
Sherry-Lily
SherrySherrySherrySherrySherrySherrySherrySherrySherrySherry

特殊屬性

python中包含了很多雙下劃線開始和結束的屬性,這些是特殊屬性,有特殊用法。這裡列出常見的特殊屬性:

#測試特殊屬性
class A():
    def say(self):
        print('aa')
class B():
    def say(self):
        print('bb')
class C(B,A):
    def __init__(self,name):
        super().__init__()
        self.name = name
c = C('sherry') 
print(c.__dict__) #c物件的屬性列表
print(c.__class__) #c物件的類
print(C.__bases__) #C類的基礎類別
print(C.__mro__)	#C類的繼承關係
print(C.__subclasses__)#C類的子類
輸出:
{'name': 'sherry'}
<class '__main__.C'>
(<class '__main__.B'>, <class '__main__.A'>)
(<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>)
<built-in method __subclasses__ of type object at 0x7fefdacc8dd0>

物件的淺拷貝和深拷貝

  • 變數的賦值操作

只是形成兩個變數,實際還是指向同一個物件。

  • 淺拷貝Python

拷貝一般都是淺拷貝。拷貝時,物件包含的子物件內容不拷貝。因此,源物件 和拷貝物件會參照同一個子物件。

  • ·深拷貝使用

使用copy 模組的 deepcopy 函數,遞迴拷貝物件中包含的子物件。源物件和拷貝物件 所有的子物件也不同。

# 測試淺拷貝和深拷貝
import copy
class MobilePhone():
    def __init__(self, cpu, screen):
        self.cpu = cpu
        self.screen = screen
class CPU():
    def caculate(self):
        print('cpu:t', self)
class Screen():
    def show(self):
        print('screen:t',self)
m1 = MobilePhone(CPU(), Screen())
print('測試賦值----')
m0 = m1
print('m1:t',m1)
m1.cpu.caculate()
m1.screen.show()
print('m0:t',m0)
m0.cpu.caculate()
m0.screen.show()
print('測試淺複製----')
m2 = copy.copy(m1)
print('m1:t',m1)
m1.cpu.caculate()
m1.screen.show()
print('m2:t',m2)
m2.cpu.caculate()
m2.screen.show()
print('測試深複製----')
m3 = copy.deepcopy(m1)
print('m1:t',m1)
m1.cpu.caculate()
m1.screen.show()
print('m3:t',m3)
m3.cpu.caculate()
m3.screen.show()
輸出:
測試賦值----
m1:      <__main__.MobilePhone object at 0x7f8b0d6ed190>
cpu:     <__main__.CPU object at 0x7f8b0d6ed130>
screen:  <__main__.Screen object at 0x7f8b0d6ed100>
m0:      <__main__.MobilePhone object at 0x7f8b0d6ed190>
cpu:     <__main__.CPU object at 0x7f8b0d6ed130>
screen:  <__main__.Screen object at 0x7f8b0d6ed100>
測試淺複製----
m1:      <__main__.MobilePhone object at 0x7f8b0d6ed190>
cpu:     <__main__.CPU object at 0x7f8b0d6ed130>
screen:  <__main__.Screen object at 0x7f8b0d6ed100>
m2:      <__main__.MobilePhone object at 0x7f8b0d6a9940>
cpu:     <__main__.CPU object at 0x7f8b0d6ed130>
screen:  <__main__.Screen object at 0x7f8b0d6ed100>
測試深複製----
m1:      <__main__.MobilePhone object at 0x7f8b0d6ed190>
cpu:     <__main__.CPU object at 0x7f8b0d6ed130>
screen:  <__main__.Screen object at 0x7f8b0d6ed100>
m3:      <__main__.MobilePhone object at 0x7f8b0d6ed280>
cpu:     <__main__.CPU object at 0x7f8b0d6ede20>
screen:  <__main__.Screen object at 0x7f8b0d6edd30>

組合

“is-a”關係,我們可以使用“繼承”。從而實現子類擁有的父類別的方法和屬性。“is-a” 關係指的是類似這樣的關係:狗是動物,dog is animal。狗類就應該繼承動物類。

“has-a”關係,我們可以使用“組合”,也能實現一個類擁有另一個類的方法和屬性。” has-a”關係指的是這樣的關係:手機擁有 CPU。 MobilePhone has a CPU。

設計模式_工廠模式實現

設計模式是物件導向語言特有的內容,是我們在面臨某一類問題時候固定的做法,設計 模式有很多種,比較流行的是:GOF(Goup Of Four)23 種設計模式。當然,我們沒有 必要全部學習,學習幾個常用的即可。

對於初學者,我們學習兩個最常用的模式:工廠模式和單例模式。

工廠模式實現了建立者和呼叫者的分離,使用專門的工廠類將選擇實現類、建立物件進行統一的管理和控制。

#測試工廠模式
class CarFactory():
    def creatCar(self, brand):
        if brand == '賓士':
            return Benz()
        elif brand == '寶馬':
            return BMW()
        elif brand == '比亞迪':
            return BYD()
        else:
            print('can not create!')
class Benz():
    pass
class BMW():
    pass
class BYD():
    pass
factory = CarFactory()
c1 = factory.creatCar('賓士')
c2 = factory.creatCar('寶馬')
c3 = factory.creatCar('比亞迪')

設計模式_單例模式實現

單例模式(Singleton Pattern)的核心作用是確保一個類只有一個範例,並且提供一個存取該範例的全域性存取點。

單例模式只生成一個範例物件,減少了對系統資源的開銷。當一個物件的產生需要比較 多的資源,如讀取組態檔、產生其他依賴物件時,可以產生一個“單例物件”,然後永久 駐留記憶體中,從而極大的降低開銷。

# 測試單例模式
class MySingleton():
    __obj = None
    __init_flag = True
    def __new__(cls, *args, **kwargs):
        if cls.__obj == None:
            cls.__obj = object.__new__(cls)  # __obj物件只建立一次  obj物件就是Mysingleton物件
        return cls.__obj
    def __init__(self, name):
        if self.__init_flag == True:
            print('init....')
            self.name = name
            self.__init_flag = False
a = MySingleton('aa')
b = MySingleton('bb')
c = MySingleton('cc')
print(a)
print(a.name)
print(b)
print(b.name)
print(c)
print(c.name)
輸出:
init....
<__main__.MySingleton object at 0x7fce0f6e8130>
aa
<__main__.MySingleton object at 0x7fce0f6e8130>
aa
<__main__.MySingleton object at 0x7fce0f6e8130>
aa

工廠模式和單例模式的整合使用

# 測試工廠模式和單例模式的混合使用
class CarFactory():
    __obj = None
    __init_flag = True
    def __new__(cls, *args, **kwargs):
        if cls.__obj == None:
            cls.__obj = object.__new__(cls)
        return cls.__obj
    def __init__(self):
        if self.__init_flag:
            print('init factory')
            self.__init_flag = False
    
    def creatCar(self, brand):
        if brand == '賓士':
            return Benz()
        elif brand == '寶馬':
            return BMW()
        elif brand == '比亞迪':
            return BYD()
        else:
            print('can not create!')
class Benz():
    pass
class BMW():
    pass
class BYD():
    pass
factory = CarFactory()
c1 = factory.creatCar('賓士')
c2 = factory.creatCar('寶馬')
c3 = factory.creatCar('比亞迪')
factory2 = CarFactory()
print(factory)
print(factory2)
輸出:
init factory
<__main__.CarFactory object at 0x7fd286eecc10>
<__main__.CarFactory object at 0x7fd286eecc10>

總結

本篇文章就到這裡了,希望能夠給你帶來幫助,也希望您能夠多多關注it145.com的更多內容!   


IT145.com E-mail:sddin#qq.com