Python 08 面向對象
Python 面向對象
1、編程範式
2、面向對象特性
3、屬性、方法
4、三大特性
5、高級方法
6、類的特殊成員方法
7、反射
一、編程範式
編程:程序員用特定的語法+數據結構+算法組成的代碼來告訴計算機如何執行任務的過程 , 實現一個任務的方式有很多種不同的方式, 對這些不同的編程方式的特點進行歸納總結得出來的編程方式類別,即為編程範式。
面向過程編程(Procedural Programming)
面向過程編程依賴:procedures,一個procedure包含一組要被進行計算的步驟,面向過程又被稱為top-down languages, 就是程序從上到下一步步執行。基本設計思路就是程序一開始是要著手解決一個大的問題,然後把一個大問題分解成很多個小問題或子過程,這些子過程再執行的過程再繼續分解直到小問題足夠簡單到可以在一個小步驟範圍內解決。這樣做的問題也是顯而易見的,就是如果你要對程序進行修改,對你修改的那部分有依賴的各個部分你都也要跟著修改,所以我們一般認為, 如果你只是寫一些簡單的腳本,去做一些一次性任務,用面向過程的方式是極好的,但如果你要處理的任務是復雜的,且需要不斷叠代和維護 的, 那還是用面向對象最方便了。
面向對象編程(Object-Oriented Programming )
面向對象編程是利用“類”和“對象”來創建各種模型來實現對真實世界的描述,使用面向對象編程的原因一方面是因為它可以使程序的維護和擴展變得更簡單,並且可以大大提高程序開發效率 ,另外,基於面向對象的程序可以使它人更加容易理解你的代碼邏輯,從而使團隊開發變得更從容。
二、面向對象的特性
類:class,一個類即是對一類擁有相同屬性的對象的抽象、藍圖、原型。在類中定義了這些對象的都具備的屬性(variables(data))、共同的方法
對象 :object,一個對象即是一個類的實例化後實例,一個類必須經過實例化後方可在程序中調用,一個類可以實例化多個對象,每個對象亦可以有不同的屬性
封裝:Encapsulation,在類中對數據的賦值、內部調用對外部用戶是透明的,這使類變成了一個膠囊或容器,裏面包含著類的數據和方法
繼承:Inheritance ,一個類可以派生出子類,在這個父類裏定義的屬性、方法自動被子類繼承
多態:Polymorphism ,多態是面向對象的重要特性,簡單點說:“一個接口,多種實現”,指一個基類中派生出了不同的子類,且每個子類在繼承了同樣的方法名的同時又對父類的方法做了不同的實現,這就是同一種事物表現出的多種形態。
三、屬性、方法
1、屬性、方法、類變量、實例變量
1 class dog: #dog:類名 2 n = 123 #基本屬性類變量 3 def __init__(self,name): 4 #構造函數 5 #在實例化時做一些類的初始化工作 6 self.name = name #實例變量(靜態屬性),作用域就是實例本身 7 def bulk(self): #類的方法(動態屬性),功能 8 print("%s:wang wang wang !"% self.name) 9 10 d1 = dog("狗") #d1 叫做dog類的實例 11 d1.bulk()
2、構造函數、析構函數、私有方法、私有屬性
1 #析構函數:在實例釋放、銷毀的時候執行的,通常用於做一些收尾工作,如關閉一些數據庫連接打開的臨時文件 2 class dog: #dog:類名 3 def __init__(self,name,age = 0): 4 #構造函數 5 #在實例化時做一些類的初始化工作 6 self.name = name 7 self.__age = age #私有屬性:只能在內部訪問和修改(私有方法同理也是在函數前面加兩個_) 8 def show_age(self): 9 print("name:%s age:%s"%(self.name,self.__age)) 10 def after_year(self): 11 self.__age += 1 12 print("一年過去了。。。") 13 def __del__(self): #析構函數 14 print(self.name) 15 r1 = dog("哈士奇") 16 r1.after_year() 17 r1.show_age()View Code
四、特性
1、封裝
封裝,顧名思義就是將內容封裝到某個地方,以後再去調用被封裝在某處的內容
將內容封裝到某處:
1 class foo: #類名 2 def __init__(self,name,age): 3 self.name = name 4 self.age = age 5 pop1 = foo("zz",12) 6 pop2 = foo("aa",13) 7 # foo相當於一類事物的模板,當執行pop1 = foo("zz",12)時 8 # 相當於在foo中:self = poo1,pop1 = foo("zz",12) 即 pop1 = foo(por1,"zz",12) 9 # 將類中的內容封裝到了對象 pop1中,而pop1有了自己的name 和 age 屬性並在內存中保存了下來封裝
從某處調用被封裝的內容
class foo: #類名 def __init__(self,name,age): self.name = name self.age = age pop1 = foo("zz",12) print(pop1.name,pop1.age) #通過對象直接調用通過對象直接調用
1 class foo: #類名 2 def __init__(self,name,age): 3 self.name = name 4 self.age = age 5 def detail(self): 6 print(self.name,self.age) 7 pop1 = foo("zz",12) 8 pop1.detail() #通過self間接調用通過self間接調用
2、繼承
繼承:面向對象中的繼承和現實生活中的繼承相同,即:子可以繼承父的內容
所以,對於面向對象的繼承來說,其實就是將多個類共有的方法提取到父類中,子類僅需繼承父類而不必一一實現每個方法
class People: def __init__(self,name,age): self.name = name self.age = age def eat(self): print("%s is eating..."%self.name) def talk(self): print("%s is talking..."%self.name) def sleep(self): print("%s is sleeping..."%self.name) class man(People): def __init__(self,name,age,money): # People.__init__(self,name,age) #重構父類構造函數 super(man,self).__init__(name,age) self.money = money def drink(self): print("%s is drinking..."%self.name) def sleep(self): People.sleep(self) #重構父類方法 print("man is sleeping...") class woman(People): def makeup(self): print("%s is makeuping..."%self.name) m1 = man("zz",12,1) m1.drink() m1 .sleep() m2 = woman("aa",10)簡單繼承
多繼承:
1、Python的類可以繼承多個類,Java和C#中則只能繼承一個類
1 # 經典類和新式類,從字面上可以看出一個老一個新,新的必然包含了跟多的功能,也是之後推薦的寫法 2 # 從寫法上區分的話,如果當前類或者父類繼承了object類,那麽該類便是新式類,否則便是經典類 3 #class People: #經典類 4 class People(object): #新式類 5 def __init__(self,name,age): 6 self.name = name 7 self.age = age 8 def eat(self): 9 print("%s is eating..."%self.name) 10 def talk(self): 11 print("%s is talking..."%self.name) 12 def sleep(self): 13 print("%s is sleeping..."%self.name) 14 class relation(object): 15 def make_friend(self,obj): 16 print("%s is making friend with %s"%(self.name,obj.name)) 17 18 class man(People,relation): 19 def __init__(self,name,age,money): 20 # People.__init__(self,name,age) #重構父類構造函數 21 super(man,self).__init__(name,age) 22 self.money = money 23 def drink(self): 24 print("%s is drinking..."%self.name) 25 def sleep(self): 26 People.sleep(self) #重構父類方法 27 print("man is sleeping...") 28 class woman(People,relation): 29 def makeup(self): 30 print("%s is makeuping..."%self.name) 31 32 m1 = man("zz",12,1) 33 w1 = woman("aa",10) 34 m1.make_friend(w1)多繼承
2、Python的類如果繼承了多個類,那麽其尋找方法的方式有兩種,分別是:深度優先和廣度優先
#經典類多繼承:深度優先 class D: def bar(self): print (‘D.bar‘) class C(D): def bar(self): print (‘C.bar‘) class B(D): def bar(self): print (‘B.bar‘) class A(B, C): def bar(self): print (‘A.bar‘) a = A() # 執行bar方法時 # 首先去A類中查找,如果A類中沒有,則繼續去B類中找,如果B類中麽有,則繼續去D類中找,如果D類中麽有,則繼續去C類中找,如果還是未找到,則報錯 # 所以,查找順序:A --> B --> D --> C # 在上述查找bar方法的過程中,一旦找到,則尋找過程立即中斷,便不會再繼續找了 a.bar() #新式類多繼承:廣度優先 class D(object): def bar(self): print (‘D.bar‘) class C(D): def bar(self): print (‘C.bar‘) class B(D): def bar(self): print (‘B.bar‘) class A(B, C): def bar(self): print (‘A.bar‘) a = A() # 執行bar方法時 # 首先去A類中查找,如果A類中沒有,則繼續去B類中找,如果B類中麽有,則繼續去C類中找,如果C類中麽有,則繼續去D類中找,如果還是未找到,則報錯 # 所以,查找順序:A --> B --> C --> D # 在上述查找bar方法的過程中,一旦找到,則尋找過程立即中斷,便不會再繼續找了 a.bar() # 經典類:首先去A類中查找,如果A類中沒有,則繼續去B類中找,如果B類中麽有,則繼續去D類中找,如果D類中麽有,則繼續去C類中找,如果還是未找到,則報錯 # 新式類:首先去A類中查找,如果A類中沒有,則繼續去B類中找,如果B類中麽有,則繼續去C類中找,如果C類中麽有,則繼續去D類中找,如果還是未找到,則報錯 # 在上述查找過程中,一旦找到,則尋找過程立即中斷,便不會再繼續找了py2版本多繼承尋找方式
從py3開始全部都是廣度優先,沒有深度優先
3、多態
Pyhon不支持Java和C#這一類強類型語言中多態的寫法,但是原生多態,其Python崇尚“鴨子類型”。
多態的作用是實現接口的重用
1 class Animal(object): 2 def __init__(self, name): # Constructor of the class 3 self.name = name 4 def talk(self): # Abstract method, defined by convention only 5 raise NotImplementedError("Subclass must implement abstract method") 6 7 class Cat(Animal): 8 def talk(self): 9 print(‘%s: 喵喵喵!‘ %self.name) 10 11 class Dog(Animal): 12 def talk(self): 13 print(‘%s: 汪!汪!汪!‘ %self.name) 14 # c1 = Cat(‘貓‘) 15 # c1.talk() 16 # d1 = Dog(‘狗‘) 17 # d1.talk() 18 # 為采用多態 19 def anmiaml(obj): #一個接口,多種形態 20 obj.talk() 21 c1 = Cat(‘貓‘) 22 d1 = Dog(‘狗‘) 23 anmiaml(c1) 24 anmiaml(d1)多態
五、高級方法
1、靜態方法
只是名義上歸類管理,實際上在靜態方法裏訪問不了類或實例中的任何屬性
1 class dog(object): 2 def __init__(self,name): 3 self.name = name 4 @staticmethod #加上之後下面的方法和類就沒有關系了 5 def eat(self): 6 print("%s is eating %s"%(self.name,"骨頭")) 7 # 通過@staticmethod裝飾器即可把其裝飾的方法變為一個靜態方法 8 # 可以在實例化後直接調用,並且在方法裏可以通過self.調用實例變量或類變量 9 # 但靜態方法是不可以訪問實例變量或類變量的,一個不能訪問實例變量和類變量的方法,其實相當於跟類本身已經沒什麽關系了 10 # 它與類唯一的關聯就是需要通過類名來調用這個方法 11 d = dog("狗") 12 # d.eat("骨頭") 未加@staticmethod時的調用 13 d.eat(d)靜態方法
2、類方法
只能訪問類變量,不能訪問實例變量
1 class dog(object): 2 name = "gou" 3 def __init__(self,name): 4 self.name = name 5 @classmethod 6 def eat(self): 7 print("%s is eating %s"%(self.name,"骨頭")) 8 def talk(self): 9 print("%s is talking.."%self.name) 10 d = dog("狗") 11 d.eat() #gou is eating 骨頭 輸出內容為類變量參數而非實例變量參數類方法
3、屬性方法
把一個方法變成一個靜態屬性
1 class dog(object): 2 name = "gou" 3 def __init__(self,name): 4 self.name = name 5 self.__food = "骨頭" 6 @property #把一個方法變成靜態屬性 7 def eat(self): 8 print("%s is eating %s"%(self.name,self.__food)) 9 @eat.setter #給靜態屬性傳參數 10 def eat(self,food): 11 print("set to food:",food) 12 self.__food = food 13 @eat.deleter 14 def eat(self): 15 del self.__food 16 print("刪除私有food!") 17 def talk(self): 18 print("%s is talking.."%self.name) 19 d = dog("狗") 20 d.eat #只能按照靜態屬性調用方式調用不能傳參數,也不能d.eat() 21 d.eat = "狗糧" #給靜態屬性傳參數 22 d.eat #狗 is eating 狗糧 23 del d.eat 24 d.eat #報錯屬性方法
六、類的特殊成員方法
1 class dog(object): 2 ‘‘‘描述狗這個對象‘‘‘ 3 ‘‘‘寫類的時候一定寫上這個類是作什麽用的‘‘‘ 4 name = "gou" 5 def __init__(self,name): 6 self.name = name 7 def eat(self): 8 print("%s is eating.."%self.name) 9 def talk(self): 10 print("%s is talking.."%self.name) 11 def __call__(self, *args, **kwargs): 12 print("run in call..",args,kwargs) 13 def __str__(self): 14 return "<obj:%s>"%self.name 15 # 1、 __doc__ 輸出:類的描述信息 16 print(dog.__doc__) #輸出:類的描述信息 (描述狗這個對象) 17 # 2、__module__ 表示當前操作的對象在那個模塊 18 # 3、__class__ 表示當前操作的對象的類是什麽 19 print(dog.__module__) #__main__ 如果這個類是import的則會返回這個類所在模塊的目錄 20 print(dog.__class__) #<class ‘type‘> 輸出這個類本身 21 # 4、__init__ 構造方法,通過類創建對象時,自動觸發執行 22 # 5、__del__ 析構方法,當對象在內存中被釋放時,自動觸發執行 23 # 6、__call__ 對象後面加括號,觸發執行 24 d = dog("狗") 25 d(1,2,3,name = 321) #輸出:run in call.. (1, 2, 3) {‘name‘: 321} 26 # 7、__dict__ 查看類或對象中的所有成員 27 print(dog.__dict__) #以一個字典的形式把類中的方法屬性全部打印,不包括實例屬性 28 print(d.__dict__) #輸出:{‘name‘: ‘狗‘} 打印所有實例屬性,不包括類屬性 29 # 8、__str__ 如果一個類中定義了__str__方法,那麽在打印 對象時,默認輸出該方法的返回值 30 print(d) #輸出:<obj:狗> 31 # 9、__getitem__、__setitem__、__delitem__ 用於索引操作,如字典。分別表示獲取、設置、刪除數 32 class Foo(object): 33 def __getitem__(self, key): 34 print(‘__getitem__‘,key) 35 def __setitem__(self, key, value): 36 print(‘__setitem__‘,key,value) 37 def __delitem__(self, key): 38 print(‘__delitem__‘,key) 39 obj = Foo() 40 result = obj[‘k1‘] # 自動觸發執行 __getitem__ 41 obj[‘k2‘] = ‘zz‘ # 自動觸發執行 __setitem__ 42 del obj[‘k1‘] # 自動觸發執行 __delitem__ 43 # 10、__new__ \ __metaclass__ 44 class Foo(object): 45 def __init__(self,name): 46 self.name = name 47 f = Foo("zz") 48 print(type(f)) #<class ‘__main__.Foo‘> 表示,obj 對象由Foo類創建 49 print(type(Foo)) #<class ‘type‘> 表示,Foo類對象由 type 類創建 50 # 即:Foo是通過type類的構造方法創建 51 # 創建類就可以有兩種方式 52 # 普通方式 53 class Foo(object): 54 def func(self): 55 print("in Foo!") 56 #特殊方式 57 def func(self): 58 print("in func!") 59 foo = type(‘foo‘,(object,), {‘func‘: func}) 60 #type第一個參數:類名 61 #type第二個參數:當前類的基類 62 #type第三個參數:類的成員 63 # 類 是由 type 類實例化產生 64 # 類默認是由 type 類實例化產生,type類中如何實現的創建類: 65 # 類中有一個屬性 __metaclass__,其用來表示該類由誰來實例化創建,我們可以為 __metaclass__ 設置一個type類的派生類,從而查看類創建的過程。 66 # 類的生成調用順序依次是 __new__ --> __init__ --> __call__特殊成員方法
七、反射
通過字符串映射或修改程序運行時的狀態、屬性、方法
1 def bulk(self): 2 print("%s is bulking..."%self.name) 3 class Dog(object): 4 def __init__(self,name): 5 self.name = name 6 def eat(self): 7 print("%s is eating..."%self.name) 8 9 d = Dog("狗") 10 choice = input(">>:").strip() 11 #輸入eat 12 print(hasattr(d,choice)) #True 13 #hasattr(obj,name_str) 判斷一個對象obj裏是否有對應的name_str字符串的方法映射 14 # print(getattr(d,choice)) #<bound method Dog.eat of <__main__.Dog object at 0x0000022F8A69C7F0>> 內存對象 15 #getattr(obj,name_str) 根據字符串去獲取obj對象裏的對應的方法的內存地址 16 if hasattr(d,choice): 17 func = getattr(d,choice) 18 func() 19 else: 20 setattr(d,choice,bulk) 21 d.bulk(d) 22 #setattr(obj,‘y‘,z) 通過字符串設置新的方法 23 #delattr 24 delattr(d,choice)反射
Python 08 面向對象