1.定義:指的是經過字符串來操做類或者對象的屬性python
2.爲何用反射?git
減小冗餘代碼,提高代碼質量。安全
3.如何用反射?框架
class People: country='China' def __init__(self,name): self.name=name obj=People('jame') #hasattr #print('country' in People.__dict__) print(hasattr(People,'country')) #getattr #print(People.__dict__['country']) #print(getattr(People,'country)) #若是取不到值,會報錯。 print(getattr(People,'country',None)) #None若是取不到值不報錯,返回None #setattr #obj.age=18 #print(obj.__dict__) setattr(obj,'age',18) print(obj.__dict__) #{'name': 'jame', 'age': 18} setattr(People,'x',111) print(People.__dict__) #{......, '__doc__': None, 'x': 111} #delattr delattr(People,'x') print(People.__dict__) #{......, '__doc__': None}
class Ftp: def get(self): print('get...') def put(self): print('put...') def auth(self): print('auth...') def run(self): while True: cmd=input('Please input:').strip() #cmd='get if hasattr(self,cmd): method=getattr(self,cmd) method() else: print('You please input error') obj=Ftp() obj.run()
動態導入模塊<瞭解>:ide
import importlib __import__('import_lib.metaclass') #這是解釋器本身內部用的 #importlib.import_module('import_lib.metaclass') #與上面這句效果同樣,官方建議用這個
isinstance(obj,cls)檢查是否obj是不是類 cls 的對象。函數
issubclass(sub,super) 檢查sub類是不是 super類的派生類。 工具
class Foo(object): pass class bar(Foo): pass obj=Foo() #1 isinstance判斷對象是否屬於某類 res1=isinstance(obj,Foo) print(res1) #True #2 issubclass 判斷bar類是不是 Foo 類的派生類 res2=issubclass(bar,Foo) print(res2) #true
2.__setattr__ ,__delattr__ ,__getattr__測試
配合反射機制使用,效果還不錯. spa
class People: country='China' def __init__(self,name): self.name=name obj=People('jame') #hasattr #print('country' in People.__dict__) print(hasattr(People,'country')) #getattr #print(People.__dict__['country']) #print(getattr(People,'country123')) #若是取不到值,會報錯。AttributeError: type object 'People' has no attribute 'country123' print(getattr(People,'country123',None)) #None若是取不到值不報錯,返回None #setattr #obj.age=18 #print(obj.__dict__) setattr(obj,'age',18) print(obj.__dict__) #{'name': 'jame', 'age': 18} setattr(People,'x',111) print(People.__dict__) #{......, '__doc__': None, 'x': 111} #delattr delattr(People,'x') print(People.__dict__) #{......, '__doc__': None}
class Foo: x=1 def __init__(self,y): self.y=y def __getattr__(self, item): print('from getattr:你找的屬性不存在.') def __setattr__(self, key, value): print('from setattr') def __delattr__(self, item): print('from delattr') self.__dict__.pop(item) #1 __setattr__ 添加、修改屬性會觸發它的執行 f1=Foo(10) #from setattr print(f1.__dict__) #{} #由於你重寫了__setattr__,凡是賦值操做都會觸發它的運行,你啥都沒寫,就是根本沒賦值,除非你直接操做屬性字典,不然永遠沒法賦值 f1.__dict__['a']=3 f1.__dict__['b']=4 print(f1.__dict__) #{'a': 3, 'b': 4} #2 __deattr__ 刪除屬性的時候會觸發 #f1.__dict__['a']=10 #咱們能夠經過修改屬性字典,來完成添加、修改屬性的操做 del f1.a #from delattr print(f1.__dict__) #{'b':4}還剩b # 3 __getattr__ 只有使用點調用屬性且屬性不存在的時候纔會觸發 f1.abc #from getattr:你找的屬性不存在.
class Ftp: def get(self): print('get...') def put(self): print('put...') def auth(self): print('auth...') def run(self): while True: cmd=input('Please input:').strip() #cmd='get if hasattr(self,cmd): method=getattr(self,cmd) method() else: print('You please input error') obj=Ftp() obj.run()
3.__getattribute__3d
# @Time : 2018/8/20 17:19 # @Author : Jame # class Foo: # def __init__(self,x): # self.x=x # # def __getattr__(self, item): # print('執行的是__getattr__') # # # # # f1=Foo(100) # print(f1.x) # f1.xxx #若訪問的不存在,則 「執行的是__getattr__」 class Foo: def __init__(self,x): self.x=x def __getattribute__(self, item): print('不論是否存在都執行的是__getattribute__') f1=Foo(200) f1.x f1.xxx
class Foo: def __init__(self,x): self.x=x def __getattr__(self, item): print('若是不存在則執行__getattr__') def __getattribute__(self, item): print('不論是否存在都執行的是__getattribute__') raise AttributeError('哈哈 嘿嘿 喲喲') f1=Foo(200) f1.x f1.xxx
#當__getattribute__與__getattr__同時存在,只會執行__getattrbute__,除非__getattribute__在執行過程當中拋出異常AttributeError
4.描述符(__get__ , __set__, __delete__)
(1).1 描述符是什麼?
描述符本質就是一個新式類,在這個新式類中,至少實現了__get__(),__set__(),__delete__()中的一個,這也被稱爲描述符協議
__get__():調用一個屬性時,觸發
__set__():爲一個屬性賦值時,觸發
__delete__():採用del刪除屬性時,觸發
#1 定義一個描述符 class Foo: def __get__(self, instance, owner): print('__get__') def __set__(self, instance, value): print('__set__') def __delete__(self, instance): print('__delete__')
(2).描述符是幹什麼的,什麼時候觸發描述符中的3個方法呢?
描述符的做用是用來代理另一個類的屬性的(必須把描述符定義成這個類的類屬性,不能定義到構造函數中__init__())
包含這三個方法的新式類稱爲描述符,由這個類產生的實例進行屬性的調用/賦值/刪除,並不會觸發這三個方法!例如:
#2 描述符的使用 class Foo2: def __get__(self, instance, owner): print('觸發 __get__') def __set__(self, instance, value): print('觸發 __set__') def __delete__(self, instance): print('觸發 __delete__') #包含這三個方法的新式類稱爲描述符,由這個類產生的實例進行屬性的調用/賦值/刪除,並不會觸發這三個方法! f2=Foo2() f2.name='jame' print(f2.name) del f2.name
#何地?:定義成另一個類的類屬性
#什麼時候?:且看下列演示
class Str: def __get__(self, instance, owner): print('Str 調用') def __set__(self, instance, value): print('str 設置') def __delete__(self, instance): print('str 刪除') class Int: def __get__(self, instance, owner): print('Int 調用') def __set__(self, instance, value): print('Int 設置') def __delete__(self, instance): print('Int 刪除') class People: name=Str() age=Int() def __init__(self,name,age): #name 被設置爲Str類的的代理,age被設置Int類的代理。 self.name=name self.age=age #何地?:定義成另一個類的類屬性 #什麼時候?:且看下列演示 p1=People('jame',18) #觸發Str 設置,Int 設置! #1 描述符str的使用 調用,設置,刪除 #p1.name #p1.name='tom' #del p1.name ''' Str 調用 str 設置 str 刪除 ''' #2 描述符int的使用 調用,設置,刪除 #p1.age #p1.age=30 #del p1.age ''' Int 調用 Int 設置 Int 刪除 ''' #3 咱們來瞅瞅到底發生了什麼? print(p1.__dict__) print(People.__dict__) #補充 print(type(p1) == People) #True,type(p1) 查看p1是哪一個類實例化來的。 print(type(p1).__dict__==People.__dict__) #True
(3).描述符分兩種
1).數據描述符:至少實現了__get__()和__set__()
1 class Foo: 2 def __set__(self, instance, value): 3 print('set') 4 def __get__(self, instance, owner): 5 print('get')
2).非數據描述符:沒有實現__set__()
class Foo: 2 def __get__(self, instance, owner): 3 print('get')
(4).注意事項:
一 描述符自己應該定義成新式類,被代理的類也應該是新式類
二 必須把描述符定義成這個類的類屬性,不能爲定義到構造函數中
三 要嚴格遵循該優先級,優先級由高到底分別是
1.類屬性
2.數據描述符
3.實例屬性
4.非數據描述符
5.找不到的屬性觸發__getattr__()
#描述符str class Str: def __get__(self, instance, owner): print('str 調用') def __set__(self, instance, value): print('Str 設置') def __delete__(self, instance): print('Str 刪除') class People: name=Str() def __init__(self,name,age): self.name=name self.age=age People.name #調用類屬性name,本質就是在調用描述符Str,觸發了__get__() People.name='egon' #賦值並無觸發__set__()的設置 del People.name #刪除也並無觸發 __del__() 的設置 #結論:描述符對類沒有做用-------->傻逼到家的結論 ''' 緣由:描述符在使用時被定義成另一個類的類屬性,於是類屬性比二次加工的描述符假裝而來的類屬性有更高的優先級 People.name #恩,調用類屬性name,找不到就去找描述符假裝的類屬性name,觸發了__get__() People.name='egon' #那賦值呢,直接賦值了一個類屬性,它擁有更高的優先級,至關於覆蓋了描述符,確定不會觸發描述符的__set__() del People.name #同上 '''
#描述符Str class Str: def __get__(self, instance, owner): print('Str調用') def __set__(self, instance, value): print('Str設置...') def __delete__(self, instance): print('Str刪除...') class People: name=Str() def __init__(self,name,age): #name被Str類代理,age被Int類代理, self.name=name self.age=age p1=People('egon',18) #str設置,觸發! #若是描述符是一個數據描述符(即有__get__又有__set__),那麼p1.name的調用與賦值都是觸發描述符的操做,於p1自己無關了,至關於覆蓋了實例的屬性 p1.name='egonnnnnn' #str設置,觸發! p1.name #str調用,觸發! print(p1.__dict__) #實例的屬性字典中沒有name,由於name是一個數據描述符,優先級高於實例屬性,查看/賦值/刪除都是跟描述符有關,與實例無關了 del p1.name #str刪除,觸發! ###數據描述符>實例屬性
class Foo: def func(self): print('我胡漢三又回來了') f1=Foo() f1.func() #調用類的方法,也能夠說是調用非數據描述符 #函數是一個非數據描述符對象(一切皆對象麼) print(dir(Foo.func)) print(hasattr(Foo.func,'__set__')) #False print(hasattr(Foo.func,'__get__')) #True print(hasattr(Foo.func,'__del__')) #False #也有人可能問,描述符不都是類嗎,函數怎麼算也應該是一個對象,怎麼就是描述符了。 #描述符是類沒問題,描述符在應用的時候不都是實例化成一個類屬性麼 #函數就是有一個非描述符類實例化獲得的一個對象 #沒錯,字符串也是同樣 f1.func='這是實例屬性啊' print(f1.func) del f1.func #刪除了非數據 f1.func() #我胡漢三又回來了
class Foo: def __set__(self, instance, value): print('foo set') def __get__(self, instance, owner): print('foo get') class Room: name=Foo() def __init__(self,name,width,length): self.name=name self.width=width self.length=length #name 是一個數據描述符,由於Name=Foo() 而Foo實現了get 和set方法,所以比實例屬性有更高的優先級 #對實例的屬性操做,觸發的都是描述符 # r1=Room('廁所',1,1) #觸發foo set # # r1.name #觸發foo get # # r1.name='廚房' #觸發 foo set class Foo1: def __get__(self, instance, owner): print('Foo1 get') class Room1: name=Foo1() def __init__(self,name,width,length): self.name=name self.width=width self.length=length #name 是一個非數據描述符,由於name=Foo1() 可是Foo1中沒有實現set方法,於是比實例屬性的優先級更低 #對實例的屬性操做,觸發的都是實例本身 r2=Room1('大廈',100,100) r2.name r2.name='高塔'
# @Time : 2018/8/24 14:56 # @Author : Jame class Foo: def func(self): print('我胡漢三回來了') def __getattr__(self, item): print('找不到了固然是來找我啦',item) f1=Foo() f1.xxxx #找不到了固然是來找我啦 xxxx
(5).描述符的使用
衆所周知,python是弱類型語言,即參數的複製沒有任何類型限制,下面咱們經過描述符機制來實現類型的功能。
class Str: def __init__(self,name): self.name=name def __get__(self, instance, owner): print('--get-->',instance,owner) return instance.__dict__[self.name] def __set__(self, instance, value): print('---set--->',instance,value) instance.__dict__[self.name]=value def __delete__(self, instance): print('---del---',instance) instance.__dict__.pop(self.name) class People: name=Str('name') def __init__(self,name,age,salary): self.name=name self.age=age self.salary=salary p1=People('egon',18,3232.3) #Str---get---> <__main__.People object at 0x0000000002866630> egon #1 調用 print(p1.__dict__) #{'name': 'egon', 'age': 18, 'salary': 3232.3} p1.name #Str--get--> <__main__.People object at 0x00000000024F6630> <class '__main__.People'> #2 賦值 print(p1.__dict__) #{'name': 'egon', 'age': 18, 'salary': 3232.3} p1.name='jame-mei' #---set---> <__main__.People object at 0x00000000024E6668> jame-mei print(p1.__dict__) #{'name': 'jame-mei', 'age': 18, 'salary': 3232.3} #3 刪除 print(p1.__dict__) #{'name': 'jame-mei', 'age': 18, 'salary': 3232.3} del p1.name #---del--- <__main__.People object at 0x0000000002566668> print(p1.__dict__) #{'age': 18, 'salary': 3232.3}
# @Time : 2018/8/24 15:12 # @Author : Jame # class Str: # def __init__(self,name): # self.name=name # # # def __get__(self, instance, owner): # print('get--->',instance,owner) # return instance.__dic__[self.name] # # # def __set__(self, instance, value): # print('set--->',instance,value) # instance.__dic__[self.name]=value # # def __delete__(self, instance): # print('delete--->',instance) # instance.__dic__.pop(self.name) # # # class People: # name=Str('name') # def __init__(self,name,age,salary): # self.name=name # self.age=age # self.salary=salary #疑問,若是我用類名去操做屬性呢 #People.name #報錯,在於把類去操做屬性,會把None傳給instance class Str: def __init__(self,name): self.name=name def __get__(self, instance, owner): print('get--->',instance,owner) if instance is None: return self return instance.__dic__[self.name] def __set__(self, instance, value): print('set--->',instance,value) instance.__dic__[self.name]=value def __delete__(self, instance): print('delete--->',instance) instance.__dic__.pop(self.name) class People: name=Str('name') def __init__(self,name,age,salary): self.name=name self.age=age self.salary=salary People.name #get---> None <class '__main__.People'> 解決
class Str: def __init__(self,name,expected_type): self.name=name self.expected_type=expected_type def __get__(self, instance, owner): print('get--->',instance,owner) if instance is None: return self return instance.__dict__[self.name] def __set__(self, instance, value): print('set--->',instance,value) if not instance(value,self.expected_type): raise TypeError('Expected %s'%str(self.expected_type)) instance.__dict__[self.name]=value def __delete__(self, instance): print('delete--->',instance) instance.__dict__.pop(self.name) class People: name=Str('name',str) #新增類型限制str def __init__(self,name,age,salary): self.name=name self.age=age self.salary=salary p1=People(123,18,333.3) #傳入的name 因不是字符串類型而拋出異常 #TypeError: 'People' object is not callable
class Typed: def __init__(self,name,expected_type): self.name=name self.expected_type=expected_type def __get__(self, instance, owner): print('get--->',instance,owner) if instance is None: return self return instance.__dict__[self.name] def __set__(self, instance, value): print('set--->',instance,value) if not isinstance(value,self.expected_type): raise TypeError('Expected %s'%str(self.expected_type)) instance.__dict__[self.name]=value def __delete__(self, instance): print('delete--->',instance) instance.__dict__.pop(self.name) class People: name=Typed('name',str) age=Typed('name',int) salary=Typed('name',float) def __init__(self,name,age,salary): self.name=name self.age=age self.salary=salary #p1=People(123,18,33.33) #set---> <__main__.People object at 0x0000000002896780> 123 #TypeError: Expected <class 'str'> #p2=People('tom','18',33.33) #set---> <__main__.People object at 0x00000000028967F0> tom #TypeError: Expected <class 'int'> p3=People('jame',18,33.33) #set---> <__main__.People object at 0x00000000024A67B8> jame #set---> <__main__.People object at 0x00000000024A67B8> 18 #set---> <__main__.People object at 0x00000000024A67B8> 33.33
通過上述幾個例子雖然能逐步實現了功能,可是問題是咱們的類有不少屬性的時候,仍然採用定義一堆屬性的方式去實現,比較low,因此須要經過裝飾器來實現:
def decorate(cls): print('類的裝飾器開始運行啦...') return cls @decorate class People1: def __init__(self,name,age,salary): self.name=name self.age=age self.salary=salary p1=People1('jame',18,33.33) #類的裝飾器開始運行啦... def typeassert(**kwargs): def decorate(cls): print('類的裝飾器開始運行啦----',kwargs) return cls return decorate @typeassert(name=str,age=int,salary=float) class People2: def __init__(self,name,age,salary): self.name=name self.age=age self.salary=salary p2=People2('jame',18,23.3) #類的裝飾器開始運行啦---- {'name': <class 'str'>, 'age': <class 'int'>, 'salary': <class 'float'>}
class Typed: def __init__(self,name,expected_type): self.name=name self.expected_type=expected_type def __get__(self, instance, owner): print('get--->',instance,owner) if instance is None: return self return instance.__dict__[self.name] def __set__(self, instance, value): print('set--->',instance,value) if not isinstance(value,self.expected_type): raise TypeError('Expected %s'%str(self.expected_type)) instance.__dict__[self.name]=value def __delete__(self, instance): print('delete--->',instance) instance.__dict__.pop(self.name) def typeassert(**kwargs): def decorate(cls): print('類的裝飾器開始運行啦---->',kwargs) for name,expected_type in kwargs.items(): setattr(cls,name,Typed(name,expected_type)) return cls return decorate @typeassert(name=str,age=int,salary=float) class People: def __init__(self,name,age,salary): self.name=name self.age=age self.salary=salary print(People.__dict__) p1=People('jame',18,28888.8) #set---> <__main__.People object at 0x00000000028C6860> jame #set---> <__main__.People object at 0x00000000028C6860> 18 #set---> <__main__.People object at 0x00000000028C6860> 28888.8
(6).描述符總結
描述符是能夠實現大部分Python類特性中的底層魔法,包括@classmethod ,@staticmethod,@property 甚至是__slots__屬性的
描述符是不少高級哭和框架的重要工具之一,描述符一般是使用到裝飾器或者元類的大型框架中的一個組件。
(7).用描述符原理完成一個自定製@property,實現延遲計算.
(本質就是把一個函數屬性利用裝飾器原理 作成一個描述符:類的類型字典中函數名爲key,valued爲描述符類產生的 對象)
class Room: def __init__(self,name,width,length): self.name=name self.width=width self.length=length @property #能夠把一個函數看成屬性來使用! def area(self): return self.width*self.length r1=Room('jame',3,4) print(r1.area)
class Lazyproperty: def __init__(self,func): self.func=func def __get__(self, instance, owner): print('這是咱們本身定製的靜態屬性, r1.area實際是要執行r1.area()') if instance is None: return self return self.func(instance) ##此時你應該明白,究竟是誰在爲你作自動傳遞self的事情 class Room: def __init__(self,name,width,length): self.name=name self.width=width self.length=length @Lazyproperty def area(self): return self.width*self.length r1=Room('tom',3,4) print(r1.area) #這是咱們本身定製的靜態屬性, r1.area實際是要執行r1.area() #12
class Lazyproperty: def __init__(self,func): self.func=func def __get__(self, instance, owner): print('這是咱們本身定製的靜態屬性,r1.area實際是要執行r1.area()') if instance is None: return self else: print('----->') value=self.func(instance) setattr(instance,self.func.__name__,value) class Room: def __init__(self,name,width,length): self.name=name self.width=width self.length=length @Lazyproperty #area=Lazyproperty(area) def area(self): return self.width*self.length r1=Room('tom',3,4) print(r1.area) #先從本身的屬性字典找,沒有再去類的中找,而後出發了area的__get__方法 print(r1.area) #先從本身的屬性字典找,找到了,是上次計算的結果,這樣就不用每執行一次都去計算
(8).用描述符原理完成一個自定製 @classmethod
class ClassMethod: def __init__(self,func): self.func=func def __get__(self, instance, owner):#類來調用,instance爲None,owner爲類自己,實例用來調用,instance爲實例,owner爲類自己 def feedback(): print('在這裏能夠加功能...') return self.func(owner) return feedback class People: name='jame' @ClassMethod #say_hi=ClassMethod(say_hi) def say_hi(cls): print('你好啊 ,帥哥 %s'%cls.name) People.say_hi() #在這裏能夠加功能... #你好啊 ,帥哥 jame p1=People() p1.say_hi() #在這裏能夠加功能... #你好啊 ,帥哥 jame #疑問:類方法若是有參數呢? class ClassMethod2: def __init__(self,func): self.func=func def __get__(self, instance, owner): def feedback(*args,**kwargs): print('在這裏能夠加功能...') return self.func(owner,*args,**kwargs) return feedback class People2: name='tom' @ClassMethod2 #say_hi=ClassMethod2(say_hi) def say_hi(cls,msg): print('你好啊,帥哥 %s %s'%(cls.name,msg)) People2.say_hi('你是那偷心的賊') #p2=People2() #p2.say_hi('你是哪偷心的賊')
(9).用描述符原理完成一個自定製 @staticmethod
class StaticMethod: def __init__(self,func): self.func=func def __get__(self, instance, owner): def feedback(*args,**kwargs): print('在這裏能夠加功能...') return self.func(*args,**kwargs) return feedback class People: @StaticMethod #say_hi=StaticMethod(say_hi) def say_hi(x,y,z): print('---->',x,y,z) People.say_hi(1,2,3) p1=People() p1.say_hi(4,5,6)
一個靜態屬性property本質就是實現了get,set,delete三種方法
8.__slots__
待更新...
1.什麼是異常?
異常就是程序運行時發生錯誤的信號(在程序出現錯誤時,則會產生一個異常,若程序沒有處理它,則會拋出該異常,程序的運行也隨之終止),在python中,錯誤觸發的異常以下:
而錯誤分紅兩種:
#語法錯誤示範一 if #語法錯誤示範二 def test: pass #語法錯誤示範三 class Foo pass #語法錯誤示範四 print(haha
#TypeError:int類型不可迭代 for i in 3: pass #ValueError num=input(">>: ") #輸入hello int(num) #NameError aaa #IndexError l=['egon','aa'] l[3] #KeyError dic={'name':'egon'} dic['age'] #AttributeError class Foo:pass Foo.x #ZeroDivisionError:沒法完成計算 res1=1/0 res2=1+'str' 2.邏輯錯誤
2.異常的種類?
在python中不一樣的異常能夠用不一樣的類型(python 中統一了類與類型,類型便是類) 去標識,一個異常標識就是一種錯誤.
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.異常處理
爲了保證程序的健壯性與容錯性,即在遇到錯誤時程序不會崩潰,咱們須要對異常進行處理,
若是錯誤發生的條件是可預知的,咱們須要用if進行處理:在錯誤發生以前進行預防
AGE=10 while True: age=input('>>: ').strip() if age.isdigit(): #只有在age爲字符串形式的整數時,下列代碼纔不會出錯,該條件是可預知的 age=int(age) if age == AGE: print('you got it') break
若是錯誤發生的條件是不可預知的,則須要用到try...except:在錯誤發生以後進行處理
#基本語法爲 try: 被檢測的代碼塊 except 異常類型: try中一旦檢測到異常,就執行這個位置的邏輯 #舉例 try: f=open('a.txt') g=(line.strip() for line in f) print(next(g)) print(next(g)) print(next(g)) print(next(g)) print(next(g)) except StopIteration: f.close()
#1 異常類只能用來處理指定的異常狀況,若是非指定異常則沒法處理。 s1 = 'hello' try: int(s1) except IndexError as e: # 未捕獲到異常,程序直接報錯 print e #2 多分支 s1 = 'hello' try: int(s1) except IndexError as e: print(e) except KeyError as e: print(e) except ValueError as e: print(e) #3 萬能異常Exception s1 = 'hello' try: int(s1) except Exception as e: print(e) #4 多分支異常與萬能異常 #4.1 若是你想要的效果是,不管出現什麼異常,咱們統一丟棄,或者使用同一段代碼邏輯去處理他們,那麼騷年,大膽的去作吧,只有一個Exception就足夠了。 #4.2 若是你想要的效果是,對於不一樣的異常咱們須要定製不一樣的處理邏輯,那就須要用到多分支了。 #5 也能夠在多分支後來一個Exception s1 = 'hello' try: int(s1) except IndexError as e: print(e) except KeyError as e: print(e) except ValueError as e: print(e) except Exception as e: print(e) #6 異常的其餘機構 s1 = 'hello' try: int(s1) except IndexError as e: print(e) except KeyError as e: print(e) except ValueError as e: print(e) #except Exception as e: # print(e) else: print('try內代碼塊沒有異常則執行我') finally: print('不管異常與否,都會執行該模塊,一般是進行清理工做') #7 主動觸發異常 try: raise TypeError('類型錯誤') except Exception as e: print(e) #8 自定義異常 class EgonException(BaseException): def __init__(self,msg): self.msg=msg def __str__(self): return self.msg try: raise EgonException('類型錯誤') except EgonException as e: print(e) #9 斷言:assert 條件 assert 1 == 1 assert 1 == 2
#10 總結try..except
1:把錯誤處理和真正的工做分開來
2:代碼更易組織,更清晰,複雜的工做任務更容易實現;
3:毫無疑問,更安全了,不至於因爲一些小的疏忽而使程序意外崩潰了;
4.何時用異常處理?
Try--except是你附加給你的程序的一種異常處理的邏輯,與你的主要的工做是沒有關係的,這種東西加太多會致使代碼可讀性變差,只有在錯誤發生的條件沒法預知的狀況下,才應該加上try ... except!