Python學習--day21
day 21
一、面向物件概述
1、什麼是面向物件:
1、面向過程的程式設計:
面向過程,核心是過程,即解決問題的步驟,編寫程式好比在設計一條流水線,為了得到合格的產品(程式),人為指定程式需要翔安什麼再幹什麼。它是一種機械式的思維方式。
優點:將複雜的問題流程化,進而簡單化(將一個複雜的問題,拆分成一個個小的問題去實現,實現小的步驟就會變得比較簡單。)
缺點:可擴充套件性差(解決問題的指向性比較強,若需求有所變動,修改幅度較大)
使用場景:對擴充套件性要求較低的軟體,比如系統核心,指令碼程式(運維工程師寫的程式,其目的就是安裝一堆軟體),Apache HTTP伺服器等; 當我們要開發的程式需非常高的擴充套件性時就不能再使用該方式了
2、面向物件的程式設計:
面向物件:核心為物件二字,物件即特徵與技能的結合體,基於面向物件的程式設計就好比在創造一個世界,而編寫程式的人就相當於是這個世界的上帝,存在的一切皆為物件,不存在的也可以被創造出來,與面向過程機械的思維方式形成鮮明的對比,面向物件更加註重對現實世界的模擬,是一種“上帝式”的思維方式。
優點:a、可擴充套件性強(對某一個物件的單獨修改,會立刻反映到整個體系中,例如在遊戲中對人物引數特性和技能的修改都會變得很容易。);
b、各個物件之間的耦合度較低,當其中一個物件出現了問題,不會對其他物件產生影響。
缺點:a、程式設計的複雜程度高於面向過程;
b、無法預知執行結果。
使用場景:需要較高的可擴充套件性時使用(直接與使用者發生互動的程式,如qq,微信);對不需要較高擴充套件性的程式而言,使用面向物件反而增加了複雜度。
2、為什麼要使用面向物件:
在開發一些需要與使用者直接打交道的程式時,因使用者的需求是不停的發生變化,所以我們要使用可擴充套件性較高的面向物件式程式設計(本質就是使用不同的物件來編寫程式)方式來編寫程式。
二、類與物件:
1、類:
類十一個抽象的概念,類即種類、類別,是面向物件設計的重要概念,是一系列的物件的相同特徵和技能的結合體。
注:現實世界中是先有物件,再有類的概念。
程式中是先定義類,然後在通過呼叫類來產生物件。
2、物件:
物件是通過呼叫類來產生獲得的,因此呼叫類的過程又稱為類例項化的過程。呼叫類會得到一個返回值,該返回值就是類的一個具體存在的物件(例項)。
#在程式中,務必保證:先定義(類),後使用(產生物件) PS: 1. 在程式中特徵用變數標識,技能(方法)用函式標識 2. 因而類中最常見的無非是:變數(特徵)和函式(方法)的定義 #程式中的類 class OldboyStudent: school='oldboy' def learn(self): print('is learning') def eat(self): print('is eating') def sleep(self): print('is sleeping') #注意: 1.類中可以有任意python程式碼,這些程式碼(函式體類的程式碼仍然存放在記憶體中,呼叫時才會執行)在類定義階段便會執行 2.因而會產生新的名稱空間,用來存放類的變數名與函式名,可以通過OldboyStudent.__dict__檢視 3.對於經典類來說我們可以通過該字典操作類名稱空間的名字(新式類有限制),但python為我們提供專門的.語法 4.點是訪問屬性的語法,類中定義的名字,都是類的屬性 5.類本省就是一個容器型別(名稱空間),用來存放名字,這是類的用途之一。 #程式中類的用法 .:專門用來訪問屬性,本質操作的就是__dict__ OldboyStudent.school #等於經典類的操作OldboyStudent.__dict__['school'] OldboyStudent.school='Oldboy' #等於經典類的操作OldboyStudent.__dict__['school']='Oldboy' OldboyStudent.x=1 #等於經典類的操作OldboyStudent.__dict__['x']=1 del OldboyStudent.x #等於經典類的操作OldboyStudent.__dict__.pop('x') #程式中的物件 #呼叫類,或稱為例項化,得到物件 s1=OldboyStudent() s2=OldboyStudent() s3=OldboyStudent() #如此,s1、s2、s3都一樣了,而這三者除了相似的屬性之外還各種不同的屬性,這就用到了__init__ #注意:該方法是在物件產生之後才會執行,只用來為物件進行初始化操作,可以有任意程式碼,但一定不能有返回值 class OldboyStudent: ...... def __init__(self,name,age,sex): self.name=name self.age=age self.sex=sex ...... s1=OldboyStudent('李坦克','男',18) #先呼叫類產生空物件s1,然後呼叫OldboyStudent.__init__(s1,'李坦克','男',18) s2=OldboyStudent('王大炮','女',38) s3=OldboyStudent('牛榴彈','男',78) #程式中物件的用法 #執行__init__,s1.name='牛榴彈',很明顯也會產生物件的名稱空間 s2.__dict__ {'name': '王大炮', 'age': '女', 'sex': 38} s2.name #s2.__dict__['name'] s2.name='王三炮' #s2.__dict__['name']='王三炮' s2.course='python' #s2.__dict__['course']='python' del s2.course #s2.__dict__.pop('course')
三、屬性查詢:
類的兩種屬性分別為資料屬性和函式屬性
1、類的資料屬性:所有物件共享
2、類的函式屬性:繫結給物件使用
注:屬性查詢的順序:obj物件產生後自己會生成一塊新的記憶體空間,obj需要呼叫屬性是首先會先從自己的空間中進行查詢,如果找不到就會到類的空間中去找,如果找不到就會到父類的空間中去找....最後找不到丟擲異常。
#類的資料屬性是所有物件共享的,id都一樣 print(id(OldboyStudent.school)) print(id(s1.school)) print(id(s2.school)) print(id(s3.school)) ''' 4377347328 4377347328 4377347328 4377347328 ''' #類的函式屬性是繫結給物件使用的,obj.method稱為繫結方法,記憶體地址都是不一樣 #ps:id是python的實現機制,並不能真實反映記憶體地址,如果有記憶體地址,還是以記憶體地址為準 print(OldboyStudent.learn) #0x1021329d8 print(s1.learn) #0x1021466d8 print(s2.learn) #0x102146710 print(s3.learn) #0x102146748 ''' <function OldboyStudent.learn at 0x1021329d8> <bound method OldboyStudent.learn of <__main__.OldboyStudent object at 0x1021466d8>> <bound method OldboyStudent.learn of <__main__.OldboyStudent object at 0x102146710>> <bound method OldboyStudent.learn of <__main__.OldboyStudent object at 0x102146748>> '''
四、類中的初始化函式
__ init__函式用於初始化物件,它會在物件剛被建立時自動執行,並傳入呼叫時傳遞的引數,第一個引數表示要初始化的物件本身。
注:呼叫類時發生的兩件事:
a、建立一個空物件stu;
b、自動觸發類中的init功能的執行,並將空物件stu和呼叫類似括號中傳入的引數一同傳入。
#方式一、為物件初始化自己獨有的特徵 class People: country='China' x=1 def run(self): print('----->', self) # 例項化出三個空物件 obj1=People() obj2=People() obj3=People() # 為物件定製自己獨有的特徵 obj1.name='egon' obj1.age=18 obj1.sex='male' obj2.name='lxx' obj2.age=38 obj2.sex='female' obj3.name='alex' obj3.age=38 obj3.sex='female' # print(obj1.__dict__) # print(obj2.__dict__) # print(obj3.__dict__) # print(People.__dict__) #方式二、為物件初始化自己獨有的特徵 class People: country='China' x=1 def run(self): print('----->', self) # 例項化出三個空物件 obj1=People() obj2=People() obj3=People() # 為物件定製自己獨有的特徵 def chu_shi_hua(obj, x, y, z): #obj=obj1,x='egon',y=18,z='male' obj.name = x obj.age = y obj.sex = z chu_shi_hua(obj1,'egon',18,'male') chu_shi_hua(obj2,'lxx',38,'female') chu_shi_hua(obj3,'alex',38,'female') #方式三、為物件初始化自己獨有的特徵 class People: country='China' x=1 def chu_shi_hua(obj, x, y, z): #obj=obj1,x='egon',y=18,z='male' obj.name = x obj.age = y obj.sex = z def run(self): print('----->', self) obj1=People() # print(People.chu_shi_hua) People.chu_shi_hua(obj1,'egon',18,'male') obj2=People() People.chu_shi_hua(obj2,'lxx',38,'female') obj3=People() People.chu_shi_hua(obj3,'alex',38,'female') # 方式四、為物件初始化自己獨有的特徵 class People: country='China' x=1 def __init__(obj, x, y, z): #obj=obj1,x='egon',y=18,z='male' obj.name = x obj.age = y obj.sex = z def run(self): print('----->', self) obj1=People('egon',18,'male') #People.__init__(obj1,'egon',18,'male') obj2=People('lxx',38,'female') #People.__init__(obj2,'lxx',38,'female') obj3=People('alex',38,'female') #People.__init__(obj3,'alex',38,'female') # __init__方法 # 強調: # 1、該方法內可以有任意的python程式碼 # 2、一定不能有返回值 class People: country='China' x=1 def __init__(obj, name, age, sex): #obj=obj1,x='egon',y=18,z='male' # if type(name) is not str: # raise TypeError('名字必須是字串型別') obj.name = name obj.age = age obj.sex = sex def run(self): print('----->', self) # obj1=People('egon',18,'male') obj1=People(3537,18,'male') # print(obj1.run) # obj1.run() #People.run(obj1) # print(People.run) !!!__init__方法之為物件定製自己獨有的特徵
五、給物件繫結方法:
1、繫結方法:
繫結方法即將物件與函式方法繫結到一起(通過將物件本身傳入函式來進行繫結),此後呼叫函式就變成了呼叫物件的方法。
注:當用物件來呼叫類中的方法時,預設會將物件傳入函式方法中,
而用類名來呼叫時,則需要手動傳入物件。
#改寫 class OldboyStudent: school='oldboy' def __init__(self,name,age,sex): self.name=name self.age=age self.sex=sex def learn(self): print('%s is learning' %self.name) #新增self.name def eat(self): print('%s is eating' %self.name) def sleep(self): print('%s is sleeping' %self.name) #注意:繫結到物件的方法的這種自動傳值的特徵,決定了在類中定義的函式都要預設寫一個引數self,self可以是任意名字,但是約定俗成地寫出self。 s1=OldboyStudent('李坦克','男',18) s2=OldboyStudent('王大炮','女',38) s3=OldboyStudent('牛榴彈','男',78) s1.learn() OldboyStudent.learn(s1) #效果同上
2、繫結方法分類:
繫結方法有兩種,一種是繫結給類的方法,一種是繫結給物件的方法。
繫結給類的方法需要使用一個裝飾器@classmethod,必須要有一個引數(類本身,預設為cls,可以自己定義,但是約定俗成的寫成使用cls)。
class Student: school = "beijing" def __init__(self,name,age,sex): self.name = name self.age = age self.sex = sex # 繫結方法分為兩種 一種是繫結給物件的,一種繫結給類的 # 繫結給類的方法 使用一個裝飾器叫classmethod,必須有一個引數,表示當前類,引數名也可以自己定義,建議不要修改 @classmethod def print_school(cls): # 輸出類裡面叫school的屬性 print(cls.school) # def print_school2(self): # 輸出類裡面叫school的屬性 # print(self.school) # 這是繫結給物件的方法 def sayHello(self): print(self.name, " 說: 你好") # Student.print_school_name() # Student.print_school()
總結:兩種繫結方法的使用場景:
a、當要處理的的資料包含在類中時,就應該繫結給類;
b、當要處理的資料包含在物件中時,就應該繫結給物件。
3、非繫結方法:
非繫結方法即在類中即不繫結給類,也不繫結給物件。
特點:沒有自動傳參的效果,類和物件都能呼叫,就是一個隸屬於類中的普通函式。
應用場景:當這個功能不許要訪問類中的資料,也不需要訪問物件的資料時,就可以作為一個非繫結方法,應用場景較少。
import json class Student: school = "oldboy" def __init__(self,name,gender,age,cla): self.name = name self.gender = gender self.age = age self.cla = cla def save(self): with open("%s.json"%self.name,"wt",encoding="utf-8") as f: json.dump(self.__dict__,f) #此處既可以使用非繫結方法也可以使用繫結給類的方法: @staticmethod #非繫結方法 def get_obj(name): with open("%s.json"%name,"rt",encoding="utf-8") as f: dic = json.load(f) stu = Student(dic["name"],dic["gender"],dic["age"],dic["cla"]) return stu # stu1 = Student("yuyu","male",18,"5") # stu1.save() stu1 = Student.get_obj("yuyu") print(stu1.gender)