Python 面向對象
1、編程范式
2、面向對象特性
3、屬性、方法
4、三大特性
5、高級方法
6、類的特殊成員方法
7、反射
8、異常處理
9、單例模式
一、編程范式?
編程:程序員用特定的語法+數據結構+算法組成的代碼來告訴計算機如何執行任務的過程 , 實現一個任務的方式有很多種不同的方式, 對這些不同的編程方式的特點進行歸納總結得出來的編程方式類別,即為編程范式。?
面向過程編程(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()
四、特性
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 = nameself.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間接調用
2、繼承
繼承:面向對象中的繼承和現實生活中的繼承相同,即:子可以繼承父的內容
所以,對于面向對象的繼承來說,其實就是將多個類共有的方法提取到父類中,子類僅需繼承父類而不必一一實現每個方法


class People:def __init__(self,name,age):self.name = nameself.age = agedef 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 = moneydef 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類中找,如果還是未找到,則報錯 # 在上述查找過程中,一旦找到,則尋找過程立即中斷,便不會再繼續找了
從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)
?八、異常處理
1、介紹
在編程過程中為了增加友好性,在程序出現報錯時一般不會將錯誤信息顯示給用戶,而是顯示一個提示的頁面。


1 name = [] 2 dir = {} 3 try: 4 dir["aa"] 5 name[2] 6 except KeyError as e: 7 print("沒有這個key:",e) 8 except IndexError as e: 9 print("列表操作錯誤:",e)


1 name = [] 2 dir = {} 3 try: 4 dir["aa"] 5 name[2] 6 open('zz.txt') 7 except KeyError as e: 8 print("沒有這個key:",e) 9 except IndexError as e: 10 print("列表操作錯誤:",e) 11 # except (KeyError,IndexError) as e: #一般不這么寫,這樣不知道是哪個觸發的 12 except Exception as e: #抓住所有錯誤 13 #對于特殊處理或提醒的異常需要先定義,最后定義Exception來確保程序正常運行 14 print(e) 15 else: 16 print("一切正常!") #如果程序沒有任何錯誤走這里 17 finally: 18 print("不管有沒有錯都執行!")
2、異常種類


#常用異常: ''' AttributeError 試圖訪問一個對象沒有的樹形,比如foo.x,但是foo沒有屬性x IOError 輸入/輸出異常;基本上是無法打開文件 ImportError 無法引入模塊或包;基本上是路徑問題或名稱錯誤 IndentationError 語法錯誤(的子類) ;代碼沒有正確對齊 IndexError 下標索引超出序列邊界,比如當x只有三個元素,卻試圖訪問x[5] KeyError 試圖訪問字典里不存在的鍵 KeyboardInterrupt Ctrl+C被按下 NameError 使用一個還未被賦予對象的變量 SyntaxError Python代碼非法,代碼不能編譯 TypeError 傳入對象類型與要求的不符合 UnboundLocalError 試圖訪問一個還未被設置的局部變量,基本上是由于另有一個同名的全局變量, 導致你以為正在訪問它 ValueError 傳入一個調用者不期望的值,即使值的類型是正確的 ''''''其他異常: ArithmeticError AssertionError AttributeError BaseException BufferError BytesWarning DeprecationWarning EnvironmentError EOFError Exception FloatingPointError FutureWarning GeneratorExit ImportError ImportWarning IndentationError IndexError IOError KeyboardInterrupt KeyError LookupError MemoryError NameError NotImplementedError OSError OverflowError PendingDeprecationWarning ReferenceError RuntimeError RuntimeWarning StandardError StopIteration SyntaxError SyntaxWarning SystemError SystemExit TabError TypeError UnboundLocalError UnicodeDecodeError UnicodeEncodeError UnicodeError UnicodeTranslateError UnicodeWarning UserWarning ValueError Warning ZeroDivisionError '''
?3、自定義異常


1 class My_Exception(Exception): 2 def __init__(self, msg): 3 self.message = msg 4 try: 5 raise My_Exception('我的異常') #主動觸發異常 6 except My_Exception as e: 7 print(e) 8
?九、單例模式


1 #單例模式:永遠用一個實例的模式 2 3 # class Foo(object): 4 # instance = None 5 # 6 # def __init__(self): 7 # self.name = 'alex' 8 # @classmethod 9 # def get_instance(cls): 10 # if Foo.instance: 11 # return Foo.instance 12 # else: 13 # Foo.instance = Foo() 14 # return Foo.instance 15 # 16 # def process(self): 17 # return '123' 18 19 # obj1 = Foo() 20 # obj2 = Foo() 21 # print(id(obj1),id(obj2)) 22 23 #low的單例模式 24 # obj1 = Foo.get_instance() 25 # obj2 = Foo.get_instance() 26 # print(id(obj1),id(obj2)) 27 28 29 #基于new方法實現單例模式 30 class Foo(object): 31 instance = None 32 33 def __init__(self): 34 self.name = 'alex' 35 36 def __new__(cls, *args, **kwargs): 37 if Foo.instance: 38 return Foo.instance 39 else: 40 Foo.instance = object.__new__(cls, *args, **kwargs) 41 return Foo.instance 42 43 # obj1 = Foo() 44 # obj2 = Foo() 45 # print(id(obj1),id(obj2))
?