Python基礎之面向對象進階詳解

面向對象三大特征介紹

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

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

多態:一個方法調用由於對象不同會產生不同的行為。

繼承

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

在這裡插入圖片描述

語法格式

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>

總結

本篇文章就到這裡瞭,希望能夠給你帶來幫助,也希望您能夠多多關註WalkonNet的更多內容!   

推薦閱讀: