面向對象編程思想 OOP
什么是面向對象:
面向對象是一種編程思想,核心是對象
程序就是一系列對象的集合,程序負責控制調度這些對象交互這完成任務
案例: 把大象裝冰箱要幾步?
面向過程思想:
1.打開冰箱
2.裝入大象
3.關閉冰箱
面向對象思想:
找一個具備裝大象功能的對象,讓這個對象去工作
思維的轉變,面向對象中,程序員從具體的操作者,變成指揮者
強調: 對象不會憑空產生,需要我們自己設計創建
優點:
1.擴展性強 (對象增加減少不影響其他對象運行)
2.靈活性
3.重用性
缺點:
1.程序的復雜程度提高了 (需要設計創建對象)
2.無法准確預知結果
使用場景
對擴展性要求較高的程序,通常是直接面對用戶的
面向過程編程思想
什么是面向過程:
其核心是過程,針對結果分析過程,按步驟一步一步執行
優點:
邏輯清晰,復雜的問題簡單化流程化.
缺點:
擴展性差(添加功能需要改動整體代碼)
維護性差
使用場景:
對擴展性要求不高的程序:系統內核,計算器...
類和對象
OOP的兩個核心概念
類
即一系列具有相同特征和行為的對象的集合
對象
是具體某個事物,具備自己的特征和行為,是特征和行為的集合體
類與對象的關系
類包含一系列對象,對象屬於某個類
現實中:先有對象再有類
編程中:先有類再有對象,我們必須要先說明這類對象具有哪些特征和行為.
ps: 先定義(類),在使用(對象)
在使用面向對象編程時,第一步思考需要什么樣的對象,對象具有什么樣的特征和行為,第二步根據這些信息總結出需要的類型
創建類和對象
創建類的語法
class 類名: '''類中的內:特征和行為''' # 描述 特征(屬性) 用 變量 # 描述 行為 用 函數 #類名的書寫: 見名知意,大駝峰體即單詞首字母大寫
注意:
1.類中可以有任意的代碼,這些代碼在類定義階段就會執行
2.類在定義階段就會產生類的名稱空間,用來存放變量和函數名,可以通過 類名.dict查看,返回的是一個字典
3.可以通過 類.變量名 或 對象.變量名 訪問這些變量的值
創建對象的語法:
class 類名: # 特征(屬性) # 行為 #創建對象,也成為實例化 obj = 類名()
注意: 實例化的對象有單獨的名稱空間,存對象放獨有的屬性
創建的對象
特征 (屬性) 的寫法
屬性寫在類中--->對象的公共屬性
屬性寫在對象中--->對象的獨有屬性
若類中和對象中存在同樣的屬性,訪問順序: 先對象再到類
練習: 描述一個老師的類,包含一個公共屬性,一個獨特屬性:
class Teacher: school = 'shanghai' obj = Teacher() obj.name = 'haha' # 相當於:obj.__dict__[name] = 'haha' print(obj.school) # >>> shanghai print(obj.name) # >>> haha
屬性的增刪改查
增加屬性:
類中: 類名.屬性名 = 值 # 類名.__dict__[屬性名] = 值 對象中: 對象名.屬性名 = 值 # 對象名.___dict__[屬性名] = 值
刪除屬性:
del 對象.屬性名 # 對象名.__dict__.pop('屬性名')
修改屬性
對象.屬性 = 值 # 對象.__dict__[屬性名] = 值
查看屬性
對象.__dict__ # 查看的是對象中所有的屬性 返回的是字典{'屬性名':值} 類名.__dict__ # 查看的是類中所有的屬性 返回的是字典{'屬性名':值}
例:
class OldTeacher: func = 'give' def run(self): # 此函數在定義類的時候也會被定義出來,但只能通過類或對象調用才能執行 print('from run') print(OldTeacher) # 類的地址 <class '__main__.OldTeacher'> tea = OldTeacher() # 對象 # 生成一個屬於OldTeacher類的對象,用tea接收,tea擁有這個類里的所有屬性 print(tea) # <__main__.OldTeacher object at 0x00000123E8387470> # 曾 屬性 tea.name = 'js' print(tea.run()) # >>> from run # 查 屬性 print(tea.name) # >>> js print(tea.func) # >>> give print(OldTeacher.func) # give print(tea.__dict__) # 打印出對象中的屬性和方法 是個字典 print(OldTeacher.__dict__) # 打印出類中的屬性和方法 是個字典 print(tea.__class__) # <class '__main__.OldTeacher'> # 對象屬於的類 print(OldTeacher.__class__) # <class 'type'> # 刪 屬性 del tea.func # 刪除類中的屬性 del tea.name # 刪除對象中的屬性 # 改 屬性 tea.func = 'xx' # 修改屬性
雙下init 方法
即初始化方法,本質是一個函數
功能:
為對象初始化自己獨有的屬性特征,即用戶給對象賦初始值
特點:
1.實例化對象時,才會執行雙下init方法
2.會自動將對象作為第一個參數傳入(默認self)
練習:創建一個類 具有幾個屬性,通過初始化方法給他們設置屬性
class Dog: def __init__(self, kind, color, age): # 給對象賦初始值,初始值就是__init__函數形參對應的實參 self.kind = kind self.color = color self.age = age # 實例化對象,開始運行__init__函數,並傳參 d1 = Dog('二哈', '黑白', 1) d2 = Dog('泰迪', '棕色', 1) # 簡便寫法 class Dog: def __init__(self, kind, color, age): lcs = locals() lcs.pop("self") self.__dict__.update(lcs) d1 = Dog('二哈', '黑白', 1) d2 = Dog('泰迪', '棕色', 1)
注意:
雙下init函數只有在實例化是才會運行,默認參數是對象本身,且不能有返回值,只能返回None
對象的精髓就是將數據和處理數據的函數整合到一起,這樣拿到一個對象就同時拿到了需要處理的數據以及處理數據的函數
例:
class Teacher: # 對象共有的屬性 ps: 無論類調用還是對象調用屬性,id都一樣 func = 'give' school = 'shanghaisc' def __init__(self, name, age): # self 是 對象本身 self.name = name self.age = age print(self) # 實例化對象t 時,是: <__main__.Teacher object at 0x000002BB0A897A20> # 實例化對象t1 時,是: <__main__.Teacher object at 0x000002BB0A897AC8> print('from __init__') #實例化對象時才調用 __init__函數 , 一定不能有返回值 #Teacher() # 類名加括號,調用類 t = Teacher('x', 2) # 調用類 初始化對象(實例化對象) 並傳參 t.weight = '50kg' print(t) # <__main__.Teacher object at 0x000002BB0A897A20> print(t.func) # give print(t.name) # x print(t.age) #2 print(t.weight) # 50kg t1 = Teacher('yy', 20) #調用類 實例化對象 並傳參 print(t1) # <__main__.Teacher object at 0x000002BB0A897AC8> print(t1.func) print(t1.name) print(t1.age)
類與對象的名稱空間
class Animal: f = '攻擊' r = ['running'] def __init__(self, name, age, hp): self.name = name self.age = age self.hp = hp def eat(self): print('吃葯回血') print(Animal.__dict__) dog = Animal('二哈', 2, 100) dog.function = '拆家' print(dog.f) # 攻擊 dog.f = '咬' # 當對象點類中的不可變靜態屬性並賦了值,會在對象的名稱空間中創建該屬性及值 print(dog.f) # 咬 dog.r[0] = 'fly' # 當對象點類中的可變靜態屬性並賦了值,只是改變了該屬性的值 print(dog.__dict__) # {'name': '二哈', 'age': 2, 'hp': 100, 'function': '拆家', 'f': '咬'}

對象的綁定方法
默認情況是下類中的方法(函數)都是對象綁定方法,方法(函數)默認傳入參數self,即對象
對象調用與類調用的區別
對象調用該方法(函數)會自動將對象本身當實參傳入,作為第一參數.
類調用時,這些方法就是一個普通函數,需要幾個參數就傳幾個參數
練習: 寫一個學生類,具備打招呼功能,要輸出自己的名字
# 對象調用時,方法會把對象傳入 class Student: def __init__(self, name): self.name = name # 實例化后生成對象的名稱空間,name放入空間里 def say_hi(self): print("hello my name is %s" % self.name) # 對象經過實例化后生成對象空間 s = Student('haha') # 等同於 Student.say_hi(s) print(s.name) s.say_hi() # >>> hello my name is haha # 用類調用函數 class Student: def say_hi(self): print("hello my name is %s" % self) # 類調用方法時,方法就是一個普通函 Student.say_hi('YY') # >>> hello my name is YY
類綁定方法
語法:
@classmethod
def 函數名():
無論類調用還是對象調用,都會自動傳入類本身,作為第一個參數
class Student: def __init__(self, name): self.name = name @classmethod def say_hi(self): print(self) # >>> <class '__main__.Student'> print(Student) # >>> <class '__main__.Student'> s = Student('YY') s.say_hi() Student.say_hi()
非綁定方法
語法 @staticmethod
即靜態方法,既不需要訪問類的數據,也不訪問對象的數據
class Student: def __init__(self, name): self.name = name @staticmethod def say_hi(): print('from say_hi') s = Student('YY') s.say_hi() # >>> from say_hi Student.say_hi() # >>> from say_hi