Python3(7) Python 面向?qū)ο缶幊?/h2>

本系列主要學(xué)習(xí)Python的基本使用和語法知識(shí),后續(xù)可能會(huì)圍繞著AI學(xué)習(xí)展開。
Python3 (1) Python語言的簡(jiǎn)介
Python3 (2) Python語法基礎(chǔ)
Python3 (3) Python函數(shù)
Python3 (4) Python高級(jí)特性
Python3(5) Python 函數(shù)式編程
Python3(6) Python 模塊
Python3(7) Python 面向?qū)ο缶幊?/a>
面向?qū)ο缶幊淌且环N編程思想,主要與面向過程編程比較學(xué)習(xí),在經(jīng)歷了 C++、C#、Java 的面向?qū)ο蟮膶W(xué)習(xí),相信學(xué)習(xí) Python 的面向?qū)ο髸?huì)讓自己對(duì) OOP 有更深的理解。

面向?qū)ο笈c面向過程的比較

面向?qū)ο缶幊獭狾bject Oriented Programming,簡(jiǎn)稱OOP,是一種程序設(shè)計(jì)思想。OOP把對(duì)象作為程序的基本單元,一個(gè)對(duì)象包含了數(shù)據(jù)和操作數(shù)據(jù)的函數(shù)。
面向過程編程——面向過程的程序設(shè)計(jì)把計(jì)算機(jī)程序視為一系列的命令集合,即一組函數(shù)的順序執(zhí)行。為了簡(jiǎn)化程序設(shè)計(jì),面向過程把函數(shù)繼續(xù)切分為子函數(shù),即把大塊函數(shù)通過切割成小塊函數(shù)來降低系統(tǒng)的復(fù)雜度。

#面向?qū)ο?class Student(object):

    def __init__(self, name, age):
        self.name = name
        self.age = age

    def print_age(self):
        print('%s: %s' % (self.name, self.age))

bart = Student('張三', 15)
lisa = Student('李四', 16)
bart.print_age()
lisa.print_age()
#面向過程
def print_age(std):
    print('%s: %s' % (std['name'], std['age']))
std1 = { 'name': '張三', 'age': 17 }
std2 = { 'name': '李四', 'age': 18 }

print_age(std1)
print_age(std2)

輸出結(jié)果:

張三: 15
李四: 16
張三: 17
李四: 18

在Python中,所有數(shù)據(jù)類型都可以視為對(duì)象,當(dāng)然也可以自定義對(duì)象。Student的實(shí)例就是一個(gè)個(gè)對(duì)象。

類與實(shí)例

類與實(shí)例與java相同,就是普通的 Class 和 Class的實(shí)例化 ,類可以看成一個(gè)模板,可以實(shí)例出不用的對(duì)象。

下面我們分析一下上面面向?qū)ο蟮?示例:

  • class Student(object) Student 類的定義,繼承自object
  • def __init__(self, name, age)含義跟java構(gòu)造函數(shù)相同,創(chuàng)建了實(shí)例時(shí)可以綁定一些數(shù)據(jù)。
  • 創(chuàng)建實(shí)例 在類名后+ ()即可,沒有new關(guān)鍵字跟kotlin 使用一致。
  • 在類中定義的函數(shù)有個(gè)共同的特點(diǎn)就是第一個(gè)參數(shù)是self。
  • Python允許對(duì)實(shí)例變量綁定任何數(shù)據(jù),與靜態(tài)語言不同。

數(shù)據(jù)封裝

數(shù)據(jù)的封裝,其實(shí)就是定義一些函數(shù),來實(shí)現(xiàn)特定的功能,類的實(shí)例調(diào)用對(duì)應(yīng)的方法就可以實(shí)現(xiàn)對(duì)應(yīng)的功能,不需要關(guān)注函數(shù)的具體實(shí)現(xiàn)和數(shù)據(jù)的具體傳遞。

訪問限制

在前面我們已經(jīng)學(xué)習(xí)過,除特殊的變量,以_xxx__xxx命名的變量是私有的,我們可以通過設(shè)置get、set來訪問私有變量。這就體現(xiàn)了代碼的封裝性,可以使我們的程序更加的安全,規(guī)范,健壯。但是不是設(shè)置成私有的就一定不能被外界直接訪問只是不符合編碼規(guī)則,例如:__namepython解釋器會(huì)編譯成_Student__name不同的版本也可能有不同的編譯方式,所以盡量不要這樣使用。

繼承

OOP程序設(shè)計(jì)中,當(dāng)我們定義一個(gè)class的時(shí)候,可以從某個(gè)現(xiàn)有的class繼承,新的class稱為子類(Subclass),而被繼承的class稱為基類、父類或超類(Base class、Super class)。繼承的作用就是子類可以繼承到父類的所有功能。也可以重寫對(duì)應(yīng)的功能。

多態(tài)

多態(tài)的概念其實(shí)是在繼承,重寫的應(yīng)用,我們可以通過繼承派生出不同的子類,重寫子類的具體實(shí)現(xiàn),在調(diào)用時(shí)用他們的共同基類做參數(shù),這樣基類派生出的各種子類都可以傳遞進(jìn)去,系統(tǒng)會(huì)根據(jù)傳入的具體類型實(shí)現(xiàn)具體的功能。

開閉原則

多態(tài)的設(shè)計(jì)采用的就是開閉原則:調(diào)用方只管調(diào)用,不管細(xì)節(jié),不需要任何更改。
1. 對(duì)擴(kuò)展開放:允許新增子類;
2. 對(duì)修改封閉:不需要修改用基類作為參數(shù)的方法

鴨子類型

這是Python強(qiáng)大之處,決定了繼承不像靜態(tài)語言那樣是必須的。
鴨子類型:不要求嚴(yán)格的繼承體系,一個(gè)對(duì)象只要“看起來像鴨子,走起路來像鴨子”,那它就可以被看做是鴨子,具體講就是傳入的對(duì)象,有需要的方法就可以傳入并使用,不需要嚴(yán)格的來自它的繼承。

下面通過一個(gè)示例來演示繼承、多態(tài)、鴨子類型:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

#基類
class Car(object):
    def run(self):
        return "car running...."
#子類
class SmallCar(Car):
    def run(self):
        return 'small car running...'
#子類
class BigCar(Car):
    def run(self):
        return 'bag car running...'
#子類的子類
class PoliceCar(SmallCar):
    def run(self):
        return 'police car running...'
    def stop(self):
        return 'police car stopped...'
#鴨子類型
class SchoolCar(object):
    def run(self):
        return 'school car running...'

#方法的調(diào)用
def look(car):
    print('I look a ',car.run())
#多態(tài)的使用場(chǎng)景
look(Car())
look(SmallCar())
look(BigCar())
look(PoliceCar())
#鴨子類型的調(diào)用
look(SchoolCar())

輸出結(jié)果:

I look a  car running....
I look a  small car running...
I look a  bag car running...
I look a  police car running...
I look a  school car running...

獲取對(duì)象信息

python中內(nèi)置了各種函數(shù),方便我們獲取對(duì)象的信息。如type()、isinstance()、dir()、getattr()setattr()以及hasattr()

下面是對(duì)獲取對(duì)象信息 內(nèi)置函數(shù)的使用示例:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

#基類
import types


class Car(object):
    weight = 2000
    def run(self):
        return "car running...."
#子類
class SmallCar(Car):
    def run(self):
        return 'small car running...'
#子類
class BigCar(Car):
    def run(self):
        return 'bag car running...'
#子類的子類
class PoliceCar(SmallCar):
    def run(self):
        return 'police car running...'
    def stop(self):
        return 'police car stopped...'
#鴨子類型
class SchoolCar(object):
    def run(self):
        return 'school car running...'

#方法的調(diào)用
def look(car):
    print('I look a ',car.run())
#type()的使用
s = SmallCar()
s1 = SmallCar()
p = PoliceCar()
c = Car()
print(type(s),type(s1))
print(type(s)==SmallCar)
print(type(s)==type(c))
print("---------------------------")
#type的高級(jí)使用
print(type(look)==types.FunctionType)
print(type(abs)==types.BuiltinFunctionType)
print(type(lambda x: x)==types.LambdaType)
print(type((x for x in range(10)))==types.GeneratorType)
print("---------------------------")
#isinstance()的使用
print(isinstance(s,SmallCar))
print(isinstance(s,Car))
print(isinstance(s,PoliceCar))
print(isinstance(s,(SmallCar,PoliceCar)))#括號(hào)中是或的關(guān)系
print("---------------------------")
#dir() 的使用
print(dir(p))
print("---------------------------")
#getattr()、setattr()、hasattr() 的使用
#屬性
print(hasattr(p,'weight'))
print(getattr(p,'weight'))
setattr(p,'weight',3000)
print(getattr(p,'weight'))
print(getattr(p,'height',404))
#方法
print(hasattr(p,'run'))
print(getattr(p,'run'))
setattr(p,'run',123456)
print(getattr(p,'run'))
#attr正確用法,去阻止鴨式類型之外的對(duì)象
def look(car):
    if hasattr(car, 'run'):
        print('I look a ', car.run())
    return None

class Ambulance(object):
    def shop(self):
        return 'ambulance car stopped...'

print(look(Ambulance()))

輸出結(jié)果:

<class '__main__.SmallCar'> <class '__main__.SmallCar'>
True
False
---------------------------
True
True
True
True
---------------------------
True
True
False
True
---------------------------
['__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__', 'run', 'stop', 'weight']
---------------------------
True
2000
3000
404
True
<bound method PoliceCar.run of <__main__.PoliceCar object at 0x0000020D453CC0F0>>
123456
None

實(shí)例屬性和類屬性

這里主要強(qiáng)調(diào)一下實(shí)例屬性與類屬性的區(qū)別,由于Python是動(dòng)態(tài)語言,根據(jù)類創(chuàng)建的實(shí)例可以任意綁定屬性。包括類的屬性

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
class Car(object):
    name = 'car'
    def __init__(self, name,weight):
        self.name = name
        self.weight = weight

c = Car('small car',2000);
print(Car.name)
print(c.name)
print(c.weight)
del c.name,c.weight
print(c.name)
print(getattr(c,'weight',3000))

輸出結(jié)果:

car
small car
2000
car
3000

從上面可以看出如果刪除了實(shí)例的屬性,實(shí)例的屬性會(huì)自動(dòng)訪問類的屬性。所以一定要注意實(shí)例的屬性名與類的屬性名不要重復(fù)。

參考

https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/0014318645694388f1f10473d7f416e9291616be8367ab5000

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容