1. 程式人生 > >Python--面向物件初體驗

Python--面向物件初體驗

面向過程

面向過程:核心是過程二字,過程即解決問題的步驟
基於該思想寫程式就類似流水線
優點:複雜的過程簡單化
缺點:擴充套件性差

面向物件

面向過程的程式設計的核心是過程(流水線式思維),過程即解決問題的步驟,面向過程的設計就好比精心設計好一條流水線,考慮周全什麼時候處理什麼東西。

優點是:極大的降低了寫程式的複雜度,只需要順著要執行的步驟,堆疊程式碼即可。

缺點是:一套流水線或者流程就是用來解決一個問題,程式碼牽一髮而動全身。

應用場景:一旦完成基本很少改變的場景,著名的例子有Linux核心,git,以及Apache HTTP Server等。
面向物件的程式設計的核心是物件(上帝式思維),要理解物件為何物,必須把自己當成上帝,上帝眼裡世間存在的萬物皆為物件,不存在的也可以創造出來。面向物件的程式設計好比如來設計西遊記,如來要解決的問題是把經書傳給東土大唐,如來想了想解決這個問題需要四個人:唐僧,沙和尚,豬八戒,孫悟空,每個人都有各自的特徵和技能(這就是物件的概念,特徵和技能分別對應物件的屬性和方法),然而這並不好玩,於是如來又安排了一群妖魔鬼怪,為了防止師徒四人在取經路上被搞死,又安排了一群神仙保駕護航,這些都是物件。然後取經開始,師徒四人與妖魔鬼怪神仙互相纏鬥著直到最後取得真經。如來根本不會管師徒四人按照什麼流程去取。

面向物件的程式設計的

優點是:解決了程式的擴充套件性。對某一個物件單獨修改,會立刻反映到整個體系中,如對遊戲中一個人物引數的特徵和技能修改都很容易。

缺點:可控性差,無法向面向過程的程式設計流水線式的可以很精準的預測問題的處理流程與結果,面向物件的程式一旦開始就由物件之間的互動解決問題,即便是上帝也無法預測最終結果。於是我們經常看到一個遊戲人某一引數的修改極有可能導致陰霸的技能出現,一刀砍死3個人,這個遊戲就失去平衡。

應用場景:需求經常變化的軟體,一般需求的變化都集中在使用者層,網際網路應用,企業內部軟體,遊戲等都是面向物件的程式設計大顯身手的好地方。

在python 中面向物件的程式設計並不是全部。

面向物件程式設計可以使程式的維護和擴充套件變得更簡單,並且可以大大提高程式開發效率 ,另外,基於面向物件的程式可以使它人更加容易理解你的程式碼邏輯,從而使團隊開發變得更從容。

瞭解一些名詞:類、物件、例項、例項化

類:具有相同特徵的一類事物(人、狗、老虎)

物件/例項:具體的某一個事物(隔壁阿花、樓下旺財)

例項化:類——>物件的過程(這在生活中表現的不明顯,我們在後面再慢慢解釋)

面向物件特點

將某些相關的功能(函式)封裝在一起;
上帝的角度建立了一個模板,通過模板建立不同的物件;
在現實世界:一定先有一個個具體存在的物件,後總結出的類
計算機世界:一定保證先定義類後產生物件
#class demo
class Person: 
    animal = "高階動物" #靜態屬性
    def __init__(self,name,age,sex): #物件屬性
        self.name = name
        self.age = age
        self.sex = sex
    
    #類的方法
    def work(self):     
        print("%s會工作,今年%s歲他是一個%s人" %(self.name,self.age,self.sex))
    
p1 = Person("jim",28,"男")  #建立物件

#結構分析:類一般分為兩部分:變數 方法
#思想分析:建立一個類:建立一個公共模板通過建立個體物件可以享有公共方
我們通過上面的栗子瞭解了類與物件的基本定義,那麼我們來分解一下上面的程式碼
1.我們有一個test類,定義了一個靜態屬性和動態方法
2.我們例項化了一個物件p1然後傳遞了3個引數

我們發現無論是__init__方法還是普通的動態方法都包含一個self,那這個self又是什麼呢?
self:在例項化時自動將物件/例項本身傳給__init__的第一個引數,你也可以給他起個別的名字,但是正常人都不會這麼做

我們定義的類的屬性到底存到哪裡了?有兩種方式檢視
1.dir(類名):查出的是一個名字列表
2.類名.__dict__:查出的是一個字典,key為屬性名,value為屬性值

特殊的類屬性
類名.__name__# 類的名字(字串)
類名.__doc__# 類的文件字串
類名.__base__# 類的第一個父類(在講繼承時會講)
類名.__bases__# 類所有父類構成的元組(在講繼承時會講)
類名.__dict__# 類的字典屬性
類名.__module__# 類定義所在的模組
類名.__class__# 例項對應的類(僅新式類中)

我們瞭解了類和物件的基本概念也知道怎麼定義一個類和物件,那麼接下來我們來介紹一下通過類名我們能幹哪些事情吧;
類名呼叫靜態屬性
class pay:
"""
這是一個支付類
"""
    name = "支付介面"

    def pay_port(self):
    print("我是一個支付介面")

    def red_packet(self):
    print("我是發紅包功能")

print(pay.__dict__)    #檢視類的名稱空間
#檢視屬性
print(pay.name)       #pay.name:類的靜態屬性

#增加屬性
pay.country = "China"
print(pay.country)

#修改
pay.country = "china"
print(pay.country)

#刪除
del pay.country
print(pay.country)
類名呼叫動態方法
#一般不建議使用類名呼叫類的動態方法,除類方法與靜態方法
class pay:
"""
這是一個支付類
"""
     name = "支付介面"

     def pay_port(self):
         print("我是一個支付介面")


     def red_packet(self):
        print("我是發紅包功能")
        
print(pay.pay_port) #呼叫類的動態方法

物件

我們也瞭解了通過類名可以做哪些事情,那麼來聊聊物件的那些事情,這裡的物件不是女朋友而是類的例項化,我們要時時刻刻記住這個概念:物件 = 類名():一個類例項化物件的過程
那麼我們來聊聊例項化物件的到底都幹了啥;
1.物件 = 類名()呼叫object類的__new__方法建立一個物件
2.物件在記憶體開闢一個物件地址空間;
3.物件記憶體空間裡有一個叫“類記憶體指標”物件通過它就能知道自己是哪個類的例項化也就自動去載入類的__init__這個特殊的方法
4.自動執行類__init__這個特殊方法,自動將物件地址空間傳遞給__init__方法的self引數;
5.在__init__方法中給物件地址空間封裝一些靜態屬性
class test:
    name = "火影忍者"    #類的靜態屬性
    def __init__(self,name,age,ad,hp):  #__init__:物件的特殊方法(用於給物件封裝靜態屬性):(self:物件空間的記憶體地址,name,age,ad,hp:物件的靜態屬性)
        self.name = name   #self.name = name:物件地址空間裡定義一個叫name的變數接收__init__方法傳遞的第一個位置引數:name
        self.age = age #同上
        self.ad = ad   #同上
        self.hp = hp   #同上
    def test(self):    #類的動態方法:self = 物件的記憶體地址空間;
        pass

you = test("宇智波鼬","男",10000,500)
print(you.name)
我們瞭解物件的定義和怎麼產生的物件,那麼介紹一下物件能做哪些事情吧;
物件呼叫類的靜態屬性
#格式:物件.類的靜態屬性
class test:
    state = "木葉"   
    def __init__(self,name,age,ad,hp): 
        self.age = age
        self.ad = ad
        self.hp = hp
    def test(self):
        pass
you = test("宇智波鼬","男",10000,500)
print(you.state)   #物件在自己的地址空間找不到就會去類查詢
print(test.state)  #直接呼叫類靜態屬性
物件呼叫類的動態方法
物件.類的動態方法
class test:
    name = "火影忍者"    #類的靜態屬性
    def __init__(self,name,age,ad,hp):  
        self.age = age
        self.ad = ad
        self.hp = hp
    def test(self,*args,**kwargs):
        print("我是一個動態屬性")
        print(args)
        return 1
you = test("宇智波鼬","男",10000,500)
print(you.test(1,2,3,4))
物件檢視自己空間的屬性
我們瞭解了物件的一些功能,那麼我們怎麼檢視物件自己的屬性呢?
class test:
    state = "中國"
    def __init__(self,name,age,sex):
        self.name = name
        self.age = age
        self.sex = sex

    def test(self):
        print("我是{},今年{}" .format(self.name,self.age))

a = test("jim",28,"Man")
print(a.__dict__)   #檢視物件屬性
print(a.state)
a.test()
通過上面的程式碼我們發現一個問題,我們可以通過物件檢視一個不在類空間的靜態屬性state,那麼介紹一下物件查詢屬性的順序
1.物件本身名稱空間
2.類的名稱空間
3.父類名稱空間
我們來總結一下:
1.類中定義的方法是繫結給物件使用的
2.不同的物件就是不同的繫結方法
3.繫結給誰就應該由誰呼叫,誰來呼叫就會把物件的記憶體地址傳遞給類方法裡的self引數
4.物件與物件之間不能互相訪問
5.類所有屬性共享,所有物件內部都包含一個"類記憶體指標":指向這個物件屬於哪個類

類即型別

#在python中接觸到的資料型別 如列表 字典 字串等其實都是一個類
a = "test"
b = 1
c = []
d = {}
e = ()
print(type(e))

#我們拿列表舉例在列表中c = [] 其實就是list這個類的物件叫c
#我們通過c.append()可以追加元素其實就是呼叫list類裡的append()方法將元素追加到a這個物件的記憶體空間

面向物件--組合

組合:物件中的屬性是另一個類的物件
組合的作用:讓類的物件與另一個類的物件發生關聯從而互相訪問
#基礎程式碼
class test:
    """
    模擬攻擊
    """
    name = "火影忍者"
    def __init__(self,name,ad,hp):
        self.name = name
        self.ad = ad
        self.hp = hp

    def fight(self,role1):
        role1.hp = role1.hp - self.ad
        print("%s攻擊了%s,%s掉了%s" %(self.name,role1.name,role1.name,role1.hp))

test1 = test("鳴人",10000,8000)
test2 = test("佐助",10000,6000)

test1.fight(test2)
#類的組合
class test:
    """
    模擬攻擊
    """
    name = "火影忍者"

    def __init__(self, name, ad, hp):
        self.name = name
        self.ad = ad
        self.hp = hp

    def eqit_weapon(self,wea):
        self.wea = wea

class weapon:
    """
    技能庫
    """
    def __init__(self, name, ad):
        self.name = name
        self.ad = ad

    def weapon_attack(self,role1,role2):
        role2.hp = role2.hp - self.ad
        print("%s使用了%s攻擊了%s,%s剩餘%s" %(role1.name,self.name,role2.name,role2.name,role2.hp))


test1 = test("鳴人", 10000, 8000)
test2 = test("佐助", 10000, 6000)
test3 = weapon("螺旋丸",100)
test4 = weapon("千鳥",70)
test1.eqit_weapon(test3)
test2.eqit_weapon(test4)
test1.wea.weapon_attack(test1,test2)
test2.wea.weapon_attack(test2,test1)

#我們來分析一下上面都做了哪些事情
#1.test這個類例項化了test1 test2;weapon類例項化了test3 test4
#2.在記憶體中開闢了4個物件地址空間存放了自己的屬性
#3.test1.eqit_weapon(test3):test1物件發現自己的物件空間沒有eqit_weapon()方法就
#通過類記憶體指標找到了自己的類呼叫了eqit_weapon()方法並將test3的記憶體地址傳遞進去
#4.test1在自己的記憶體空間新建了一個靜態屬性:wea對應的值是test3的記憶體地址空間
#5.test2同理
#6.test1這個物件呼叫自己的記憶體空間裡的wea屬性然後指向到了test3的地址空間
#7.在test3的地址空間裡通過類記憶體指標找到了weapon_attack()方法並將test1和test2傳遞進去
#8.由於呼叫weapon_attack()方法的屬於test3所以self.name是test3記憶體空間裡的name並不是test1裡的name