python_way day8
一、面向对象三大特性:
多态
二、面向对象中的成员
字段、方法属性
三、成员修饰符
四、特殊成员
__init__、__doc__、__call__、__setitem__、__getitem__、___delitem__、__str__、__all__
五、面向对象其他
--isinstance
--issubclass
--继承2.7
--应用:1、自定义类型(做一个有序的字典)
2、源码的扩展
六、设计模式之单例模式
七、异常处理
一、多态
python里面定义一个函数,可以传入不同类型的变量
def func(arg):
print(arg)
但是在c#/java中,arg这个参数必须要指定类型 '
如果在定义是指定了int类型数据,此时传入了str类型,就会报错了
在python中可传入任意类型这就是多态的一个表现
在java中如果想让java中支持多态,就要用继承来实现多态了
比如:
def func(int arg)
print(arg)
这个int可以是int和int的派生类
Class A: pass Class B(A): pass Class C(A): pass def func(A arg): print(arg) 此时arg前面就可以是A/B/C三种类型了。 因为此时你要是写进入一个C类型,你又传入一个A类。它先回判断是不是属于C类,不属于就往他的父类上面找。就找到了A。
二、python面向对象的类成员
字段、方法、属性
1、字段:
静态字段,普通字段
静态字段的好处class Province:
def __init__(self,name): self.name = name self.county = "中国" hn = Province("河南")
county = hn.county #普通字段用对象访问字段 hb = Province("河北") #这样每个创建出一个对象中都保存着省份名字,和中国 #有很多省份的时候重复储存中国,耗费内存 如果使用静态字段 class Province: county = "中国" def __init__(self,name): self.name = name a = Province.county 访问静态字段用类名访问
#在python中静态字段也可以用对象访问,但是尽量别用,如果哪一天改版,不让用了,你的代码就要重构。。。
print(a) 中国 #county保存在类中,不用创建对象也可以访问静态字段,因为静态字段是属于类 #这样大家共用这一个静态字段
访问规则:
普通字段,用对象访问
静态字段,用类访问,如果在你找不到类的时候万不得已了,用一下。
2、方法
普通方法,静态方法,类方法
类中的而函数增加一个self就是方法
普通方法:
普通方法属于类,是由对象调用执行
静态方法:
class Foo: def __init__(self,name): self.name = name self.age = 18 def show(self): print(self.name) def arg(self): print(self.age) #创建一个静态方法 #这个方法用不到这个类的对象,所以把self去掉,支持传参数 @staticmethod def f1(arg1): #参数任意,可有可无 print(arg1) return True
#静态方法属于类,所有不用创建对象就可以调用 a = Foo.f1("静态方法") #执行, 类执行,也可以用对象执行,不到万不得已不要这么用。 print(a)
静态方法
True
其实静态方法和函数的功能是一样的,只不过它属于一个类,用处就是这个方法可能和这个类有某种关系,就是为了归类
类方法:
属于静态方法的特殊形式
class Foo: def __init__(self,name): self.name = name self.age = 18 def p1(self): print(self.name) @staticmethod #静态方法 def f1(arg1): print(arg1) return True @classmethod #类方法 def f2(cls):# cls是必须有的参数,在cls就像是函数中的self,cls就是类自己本身 print(cls) cls.f1("类方法直接调用静态方法") t1 = cls("类方法调用普通方法") t1.p1()#类方法调用普通方法
Foo.f2() #执行 由类执行,也可以对象执行,但是不到万不得已不要这么用。
<class '__main__.Foo'>
类方法直接调用静态方法
类方法调用普通方法
3、属性
具有方法的写作形式,具有字段的访问形式
属性本质就是方法,只是用访问字段的方式来执行方法
class pager: def __init__(self, all_count, pager_count): self.all_count = all_count self.pager_count = pager_count def all_pager(self): k1, k2 = divmod(self.all_count, self.pager_count) if k2 == 0: return k1 else: return k1 + 1 @property #加上这个装饰器在执行这个方法就不用加括号了 def all_pager1(self): k1, k2 = divmod(self.all_count, self.pager_count) if k2 == 0: return k1 else: return k1 + 1 a = pager(101, 10) print(a.all_count) #这样的写法是获取字典 pager_num = a.all_pager() #这样的写法是执行方法
pager_num1 = a.all_pager1 #这样写法就是用 获取字段的方式 执行方法
属性的扩展用法:
我们可以以调取字段的写法 来执行 方法
哪先来看看字段都可以干什么
ret = a.all_count #这是读取字段中的值 这个写法对应属性是 pager_num1 = a.all_pager1
a.all_count = 105 #这是重新给字段赋值 这个写法对应属性是什么 ???
del a.all_count #这是删除字段 这个写法对应属性有是什么 ???
我们来看看怎么用赋值的方法来操作
class pager: def __init__(self, all_count, pager_count): self.all_count = all_count self.pager_count = pager_count @property #加上这个装饰器在执行这个方法就不用加括号了 def all_pager1(self): k1, k2 = divmod(self.all_count, self.pager_count) if k2 == 0: return k1 else: return k1 + 1 @all_pager1.setter #将具有属性的方法名作为这个方法的装饰器 + setter, def all_pager1(self,value): #并且这个方法的名称和具有属性功能的方法名称相同 print(value)
a.all_pager1 = 106 #这样就可以将106这个值传入类中的all_pager1(value)这个方法中了
106
哪del 字段 这个写法在属性中怎么使用呢?class pager:
def __init__(self, all_count, pager_count): self.all_count = all_count self.pager_count = pager_count def all_pager(self):#普通方法 k1, k2 = divmod(self.all_count, self.pager_count) if k2 == 0: return k1 else: return k1 + 1 @property #属性 k1, k2 = divmod(self.all_count, self.pager_count) if k2 == 0: return k1 else: return k1 + 1def all_pager1(self): print("del all_pager1")
a = pager(101,10)
del a.all_pager1
属性的主流表达方式
################################# 定义 ####################################################
class Foo: def __init__(self,num): self.num = num def get_num(self): return self.num def set_num(self,value): print( self.num + value ) def del_num(self): print( self.num - 1) foo = property(fget=get_num,fset=set_num,fdel=del_num) ################################### 调用 ################################################# obj = Foo(5) result1 = obj.foo #去执行foo中的 fget对应的方法 print(result1) obj.foo = 5 #去执行foo中的 fset对应的方法 del obj.foo #去执行foo中的 fdel对应的方法
注意:Python WEB框架 Django 的视图中 request.POST 就是使用的静态字段的方式创建的属性
class WSGIRequest(http.HttpRequest): def __init__(self, environ): script_name = get_script_name(environ) path_info = get_path_info(environ) if not path_info: # Sometimes PATH_INFO exists, but is empty (e.g. accessing # the SCRIPT_NAME URL without a trailing slash). We really need to # operate as if they'd requested '/'. Not amazingly nice to force # the path like this, but should be harmless. path_info = '/' self.environ = environ self.path_info = path_info self.path = '%s/%s' % (script_name.rstrip('/'), path_info.lstrip('/')) self.META = environ self.META['PATH_INFO'] = path_info self.META['SCRIPT_NAME'] = script_name self.method = environ['REQUEST_METHOD'].upper() _, content_params = cgi.parse_header(environ.get('CONTENT_TYPE', '')) if 'charset' in content_params: try: codecs.lookup(content_params['charset']) except LookupError: pass else: self.encoding = content_params['charset'] self._post_parse_error = False try: content_length = int(environ.get('CONTENT_LENGTH')) except (ValueError, TypeError): content_length = 0 self._stream = LimitedStream(self.environ['wsgi.input'], content_length) self._read_started = False self.resolver_match = None def _get_scheme(self): return self.environ.get('wsgi.url_scheme') def _get_request(self): warnings.warn('`request.REQUEST` is deprecated, use `request.GET` or ' '`request.POST` instead.', RemovedInDjango19Warning, 2) if not hasattr(self, '_request'): self._request = datastructures.MergeDict(self.POST, self.GET) return self._request @cached_property def GET(self): # The WSGI spec says 'QUERY_STRING' may be absent. raw_query_string = get_bytes_from_wsgi(self.environ, 'QUERY_STRING', '') return http.QueryDict(raw_query_string, encoding=self._encoding) # ############### 看这里看这里 ############### def _get_post(self): if not hasattr(self, '_post'): self._load_post_and_files() return self._post # ############### 看这里看这里 ############### def _set_post(self, post): self._post = post @cached_property def COOKIES(self): raw_cookie = get_str_from_wsgi(self.environ, 'HTTP_COOKIE', '') return http.parse_cookie(raw_cookie) def _get_files(self): if not hasattr(self, '_files'): self._load_post_and_files() return self._files # ############### 看这里看这里 ############### POST = property(_get_post, _set_post) FILES = property(_get_files) REQUEST = property(_get_request) Django源码
所以,定义属性共有两种方式,分别是【装饰器】和【静态字段】,而【装饰器】方式针对经典类和新式类又有所不同。
三、成员修饰符
公有、私有
成员修饰符是对类成员设置权限的,成员:字段,方法,属性
公有:字段
在类的外部和内容部都能访问的字段,就是公有字段
私有:普通字段
哪继承可以访问吗?
class Foo: def __init__(self, name): self.__name = name def f1(self): print(self.__name) obj = Foo("han") print(obj.__name) obj.f1() class F1(Foo): def f1(self): print(self.__name) obj1 = F1("han") print(obj1.f1())
AttributeError: 'Foo' object has no attribute '__name'
继承也不能访问私有字段,只能自己类内部访问
私有:静态字段
class Foo: __CC = 123 def __init__(self, name): self.__name = name def f1(self): print(self.__name)
@classmethod #类方法调用自己
def f2(cls):
return cls.__CC
@staticmethod #静态方法调用
def f3(cls):
return cls.__CC
######### 调用私有静态字段 ######### ret = Foo.__CC
print(ret)
也是不能c从外部访问
只能从类的内部访问
ret = Foo.f2
ret2 = Foo.f3(Foo)
print(ret)
print(ret2)
123
123
私有:普通方法
class Foo: __CC = 123 def __init__(self, name): self.__name = name def __f1(self): print(self.__name) def t1(self,obj): obj.__f1()
obj = Foo("han")
obj.__f1() #这样是执行不了这个方法的
obj.t1(obj) 只能这样从内部调用
私有:静态方法
类方法:
class Foo: __CC = 123 def __init__(self, name): self.__name = name @classmethod def __f2(cls): return cls.__CC def t2(self): return self.__f2() obj = Foo("han") obj.__f2() #这样是执行不了的 ret = obj.t2() 这样内部调用t2,来间接的在内部执行__f2私有方法
print(ret)
123
静态方法
class Foo: __CC = 123 def __init__(self, name): self.__name = name @staticmethod def __f3(cls): (需要方法参数) #定义了一个私有方法 return cls.__CC def t3(self,cls): #内部定义了一个方法,访问上面的私有方法 return self.__f3(cls) obj = Foo("han") obj.t3(Foo) #也需要在内部调用
#python中也可以访问私有方法
############################ 定义 静态私有字段、私有字段、静态私有方法 #########################
class Foo: __CC = 123 #静态私有字段 def __init__(self, name): self.__name = name #静态字段 @staticmethod def __f3(cls): (需要方法参数) #定义了一个静态私有(类)方法 return cls.__CC def t3(self,cls): #内部定义了一个方法,访问上面的私有方法 return self.__f3(cls)
######################## 调用 ############################################################
#1、我们想从外部直接访问私有方法
obj = Foo("han")
ret = obj._Foo__f3
print(ret)
#2、我们想从外部直接访问私有静态字段
ret1 = Foo._Foo__CC(使用类访问静态私有字段)
ret2 = obj._Foo__CC(使用函数访问静态私有字段---不建议使用)
#3、我们从外部直接访问私有字段
ret3 = obj._Foo__name
_Foo 就是后门
print(ret1,ret2,ret3)
写法:_类名__方法
四、面向对象中特殊成员
特殊成员就是 __ XXX__,两边有下划线的。
1、__init__ : 构造方法,创建对象自动执行
obj = Foo() 此时对象刚出生,这时是自动执行__init__
2、__del__ : 析构方法,垃圾回收机制马上要清除不用的对象时就会执行这个方法
等我们不用这obj的时候。垃圾回收机制就会清除这个对象,在清除之前的一刹那,要是有__del__ 就会自动执行__del__.没有就直接清除。
3、__doc__ : 把类的注释保存在里面
4、__module__ & __class__
module:在创建一个对象时,想要知道这个对象在那个模块中
class : 这个对象的类名是什么
shuxing
<class 'shuxing.Foo'> #如果在相同的模块下就会显示 <class '__main__.Foo'>
5、__call__
class Foo: def __init__(self,arg1): self.name = arg1 def __call__(self,arg2): return arg2 obj = Foo("init") #类后面加() 是执行__init__ 方法 print(obj.name) ret = obj("call") #对象后面加() 是执行 __call__ 方法 print(ret)
init
call
class Foo: def __init__(self): print("init") def __call__(self): print("call") Foo()() #先执行构造方法,再执行call方法
init
call
#这个知道就可以了
6、__str__
打印一个创建好的对象,在没有定义str的时候 只会打印这个对象的内存地址
定以后就会打印这个方法下面return的内容
class Foo: def __init__(self,name): self.name = name def __str__(self): return self.name obj = Foo("han") print(obj), #不打印就用str(obj)来回去到return的值 han ret = str(obj) print(ret) han
7、__and__
用途:两个对象相加,就会执行前面对象中定义的 __add__ 方法
lass Foo: def __init__(self,name, age): self.name = name self.age = age def __add__(self, other): msg = "%s - %d" % (self.name, other.age) return msg obj1 = Foo("han",20) obj2 = Foo("shi",40) ret = obj1 + obj2 #self 则是 obj1 ,other 则是obj2 print(ret) han - 40
8、__dict__
用途:将对象中所有封装的字段取出来
#dict 自己不用写,对象中默认就有
class Foo: __CC = 123 BB = 000 def __init__(self,name, age): self.name = name self.age = age def __add__(self, other): msg = "%s - %d" % (self.name, other.age) return msg obj1 = Foo("han",20) obj2 = Foo("shi",40) ret1 = obj1.__dict__ ret2 = Foo.__dict__ print(ret1," ",ret2) {'age': 20, 'name': 'han'} {'__module__': '__main__', '__add__': <function Foo.__add__ at 0x0000000D688CF2F0>, '__doc__': None, '__weakref__': <attribute '__weakref__' of 'Foo' objects>, 'BB': 0, '_Foo__CC': 123, '__dict__': <attribute '__dict__' of 'Foo' objects>, '__init__': <function Foo.__init__ at 0x0000000D688CF268>}
9、 obj[] 这种写法是什么鬼?
基本操作
a、__getitem__
提问:
dic = {"k1":123} #创建dic字段 dic = dict("k1" = 123) d1 = dic["k1"] #获取k1的value dic["k1"] = 345 #给k1的value 改值
del dic["k1"] #删除
在一个对象后面加() obj()执行call方法
那么在对象后面加[] obj[] 是什么鬼?这个语法到底是执行什么方法呢?
obj[] 这么写就是执行 __gititem__方法
lass Foo: __CC = 123 BB = 000 def __init__(self,name, age): self.name = name self.age = age def __getitem__(self, item=None): if not item: print("getitem") else: print(item) obj = Foo("han",123) obj["ab"] getitem
语法:在执行obj[]语法的时候就会执行 __getitem__这个方法,然后会把【】中的值传进item中
b、__setitem__
obj[] = 123 这么写就是执行 __setitem__方法
class Foo: __CC = 123 BB = 000 def __init__(self,name, age): self.name = name self.age = age def __setitem__(self, key, value): print(key,value) obj = Foo("han",123) obj["ab"] = 444 ab 444
c、__delitem__
del obj[]这么写就是执行__delitem__方法
class Foo: __CC = 123 BB = 000 def __init__(self,name, age): self.name = name self.age = age def __delitem__(self, key): print(key,"del") obj = Foo("han",123) del obj["ab"] ab del
用处:自定义session框架时会使用
===================================================================
切片方式操作
obj[1:2] 这样我们怎么操作?
class Foo: __CC = 123 BB = 000 def __init__(self,name, age): self.name = name self.age = age def __getitem__(self, item): print(type(item)) obj = Foo("han",123) ret = obj[1:5] <class 'slice'>
__getitem__
obj[1:2] 还是用的 getitem 方法
所以obj[1:2]传入的类型是slice
那我们怎么操作这样传入的数据哪?
python3中就这样做的
obj[1:5:4] = [11,22,33,44]
__setitem__
obj[1:5:4] = [11,22,33,44] 也是用的 __setitem__方法
del obj[1:5:4]
__delitem__
del obj[1:5:4]也是用的 __deltiem__方法
10、__iter__
让对象的返回值迭代起来
默认返回的对象是不可迭代的
class Foo: def __init__(self,num): self.num = num def test(self): return self.num obj = Foo([1,2,3,4]) for i in obj: print(i) TypeError: 'Foo' object is not iterable 默认对象是不能迭代的
使用__iter__ 方法后,迭代这个对象时,就会默认执行类中的__iter__方法。
class Foo: def __init__(self,num): self.num = num def test(self): return self.num def __iter__(self): return iter(self.num) obj = Foo([1,2,3,4]) for i in obj: print(i) 1 2 3 4
使用生成器来做一个可迭代对象
class Foo: def __init__(self,num): self.num = num def test(self): return self.num def __iter__(self): for i in self.num: yield i 1 2 3 4
对象被迭代的步骤,1、将对象放到for中,2、找对象中的__iter__方法,3、__iter__中返回值可以被迭代。 ''
11、 __all__
这个特殊方式是在被倒入的时候生效的
比如我们有2个module 一个是 test1,一个是test2
test2 要倒入test1 中的类我们可以有几种方式
1. import test1.Foo1 ... ...
2.import test1
3.from test1 import Foo1
4.from test1 import *
目前测试 __all__ 是在最后一种方式倒入的时候生效
如果我们在test1中定义了 __all__ , from test1 import * 时只会找到再__all__ 里面定义的类做倒入
test1.py
__all__ = ["Foo1", "Foo2"] class Foo1: def f1(self): print("foo1") class Foo2: def f1(self): print("foo2") class Foo3: def f1(self): print("foo3") class Foo4: def f1(self): print("foo4")
test2.py
from test1 import * #如果这样倒入就只能找到Foo1,和Foo2,因为Foo3和Foo4没有在test1的__all__列表中 a = Foo1() a.f1() b = Foo2() b.f1() c = Foo3() c.f1() d = Foo4() d.f1()
五、面向对象中其他的知识点
1、isinstence
判断这个对象是不是某个类的子类
class Foo: def __init__(self,num): self.num = num def test(self): return self.num def __iter__(self): for i in self.num: yield i obj = Foo([1,2,3,4]) ret = isinstance(obj,Foo) print(ret) True
补充:Foo,可以是bar的类型,也可以是bar的父类。
class Bar: pass class Foo(Bar): def __init__(self,num): self.num = num def test(self): return self.num def __iter__(self): for i in self.num: yield i obj = Foo([1,2,3,4]) ret = isinstance(obj,Bar) print(ret)
2、issubclass
查看一个类是不是另一个类的子类
class Foo: def __init__(self,num): self.num = num def test(self): return self.num def __iter__(self): for i in self.num: yield i class Bar(Foo): pass obj = Foo([1,2,3,4]) ret = issubclass(Bar,Foo) print(ret) True
3、super()
执行父类中相同名称的方法
class C1: def f1(self): print("c1.f1") class C2(C1): def f1(self): print("c2.f1") obj = C2() obj.f1() #因为子类和父类同时都有一个f1方法,所以优先执行子类C2中的函数
此时我要是想主动的执行以下父类C1的函数怎么办?
class C1: def f1(self): print("c1.f1") return 123 class C2(C1): def f1(self): a = super(C2,self).f1() #这一步就是主动的先执行父类中的f1方法,并可以获取f1方法中的返回值 print(a) obj = C2() obj.f1() c1.f1 #先执行C1中的f1方法 123 #再执行C2中的f1方法
私用场景:假如使用了大型的第三方架构,如果某一个功能不是你想要的,想要增加一点功能,如果你修改源码,不好,就自己写一个类,然后继承原来的源码使用super就可以
#另一种非主流的写法 class C1: def f1(self): print("c1,f1") return 123 class C2(C1): def f1(self): C1.f1(self) #执行C1这个类的f1方法,但是要讲自己的self传进去。 #这样也可以主动执行父类的f1方法
应用
/banchend/commons.py 源码
class Foo: def f1(self): print('Foo.f1') #源码的代码,我们要在不改动源码的前提下在 print(‘Foo.f1’)的上面和下面分别输出句话
from settings import ClassName from settings import Path def execute(): module = __import__(Path,fromlist=True) if hasattr(module,ClassName): cls = getattr(module,ClassName) obj = cls() obj.f1() else: print("no module") if __name__ == '__main__': execute()
from backend import commons class New_Foo(commons.Foo): #新的类继承源码类 def f1(self): print("befor") #上面多输出一行 super(New_Foo,self).f1()#使用super来强制调用父类f1方法 print("after") #下面多输出一行
Path = "NewFoo" #这个就对应着反射查找的位置 ClassName = "New_Foo" #这个对应着新的类
4、制作一个有序的字典
思路,在字典的基础上进行操作,字典没有提供有序的功能,我就提供这个没有的功能
class MyDict(dict): def __init__(self): self.li = [] #我的init方法,但是我们又还要使用dict的init方法 super(MyDict,self).__init__()#这样就保留下来了源码的init方法 def __setitem__(self, key, value): self.li.append(key) #将key添加到自己维护的列表中 , 但是我们key,value没有传入到字典中去 super(MyDict, self).__setitem__(key,value) #那就再使用父类的setitem方法来保存key,value def __delitem__(self, key): #删除字典用某个元素 num = self.li.index(key) #从列表中找到key的位置 del self.li[num] #从列表中删除 super(MyDict, self).__delitem__(key) #还要从字典中删除,那就交给父类的delitem把 def __str__(self): #orint的时候展示 new_list = [] for k in self.li: #循环遍历自定义的key列表 v = self.get(k) #用继承过来的get功能获取到对应的velue new_list.append("'%s':%s" % (k, v)) #将key和velue 按照 key:velue的方式保存到新的空列表中 temp_str = ",".join(new_list) #以,分割转换成为字符串 temp = "{" + temp_str + "}" #前后各加上大括号 return temp #输出
执行
###### 生成对象 ############## from My_Dict import MyDict obj = MyDict() ###### 赋值 ################# #此时使用了__setitem__ 功能 obj["k1"] = [1,2,3] obj["k2"] = [2,3,4] obj["k3"] = [4,5,6] ####### 删除 ################ #此时使用了__delitem__ 功能 del obj["k1"] ####### 输出 ################ #此时使用了__str__功能 print(obj,type(obj))
六、设计模式——单例模式
表示只有一个实例,一个对象:
用来创建单个实例:
class C1: instance = None #静态字段 def __init__(self,name): self.name = name def __str__(self): return self.name @classmethod def get_inistance(cls): #创建个类方法 if cls.instance: #如果此时的静态字段为真 return cls.instance #返回这个静态字段 else: #不为真,也就是第一次访问 obj = cls("han") #对这个类创建一个对象 cls.instance = obj #然后赋值给静态字段 return obj #然后返回这个对象 obj = C1.get_inistance() obj1 = C1.get_inistance() print(id(obj)) print(id(obj1)) 949172666552 949172666552
第一次创建对象,将对象赋值给静态字段,再次要创建对象时会去看看静态字段里面,有值则会把之前在类中生成的obj返回出来。
通过静态字段保存对象状态,下次再来时直接返回。
七:异常处理
在编程过程中为了增加友好性,在程序出现bug时一般不会将错误信息显示给用户,而是现实一个提示的页面,通俗来说就是不让用户看见大黄页!!!
try: pass 如果准确就执行try中代码 except Exception,ex: #如果有错误就执行这里面的代码 pass
1、普通异常处理
while True: num1 = input('num1: ') num2 = input("num2: ") num1 = int(num1) num2 = int(num2) ret = num1 + num2 #如果num1 或 num2 不为 整数类型就会报错 ValueError: invalid literal for int() with base 10: 'ads' #然后程序就终止了
while True: num1 = input('num1: ') num2 = input("num2: ") try: #如果正常,则执行try里的代码 num1 = int(num1) num2 = int(num2) ret = num1 + num2 except Exception as ex: #如果不正常,报错被Exception截获,并创建ex对象,然后打印ex。这样就不会因为报错,导致程序终止了。 print(ex)
2、多种异常种类
1 AttributeError 试图访问一个对象没有的树形,比如foo.x,但是foo没有属性x 2 IOError 输入/输出异常;基本上是无法打开文件 3 ImportError 无法引入模块或包;基本上是路径问题或名称错误 4 IndentationError 语法错误(的子类) ;代码没有正确对齐 5 IndexError 下标索引超出序列边界,比如当x只有三个元素,却试图访问x[5] 6 KeyError 试图访问字典里不存在的键 7 KeyboardInterrupt Ctrl+C被按下 8 NameError 使用一个还未被赋予对象的变量 9 SyntaxError Python代码非法,代码不能编译(个人认为这是语法错误,写错了) 10 TypeError 传入对象类型与要求的不符合 11 UnboundLocalError 试图访问一个还未被设置的局部变量,基本上是由于另有一个同名的全局变量, 12 导致你以为正在访问它 13 ValueError 传入一个调用者不期望的值,即使值的类型是正确的
1 ArithmeticError 2 AssertionError 3 AttributeError 4 BaseException 5 BufferError 6 BytesWarning 7 DeprecationWarning 8 EnvironmentError 9 EOFError 10 Exception 11 FloatingPointError 12 FutureWarning 13 GeneratorExit 14 ImportError 15 ImportWarning 16 IndentationError 17 IndexError 18 IOError 19 KeyboardInterrupt 20 KeyError 21 LookupError 22 MemoryError 23 NameError 24 NotImplementedError 25 OSError 26 OverflowError 27 PendingDeprecationWarning 28 ReferenceError 29 RuntimeError 30 RuntimeWarning 31 StandardError 32 StopIteration 33 SyntaxError 34 SyntaxWarning 35 SystemError 36 SystemExit 37 TabError 38 TypeError 39 UnboundLocalError 40 UnicodeDecodeError 41 UnicodeEncodeError 42 UnicodeError 43 UnicodeTranslateError 44 UnicodeWarning 45 UserWarning 46 ValueError 47 Warning 48 ZeroDivisionError
实例:
dic = ["han","xu"] #一共就2个元素 try: dic[10] #这里却获取第10个元素 except IndexError as ex: #indexerror就是捕获索引错误的 print(ex)
dic = {'k1':'v1'} try: dic['k20'] except KeyError as ex: print(ex)
s1 = 'hello' try: int(s1) except ValueError as ex: print(ex)
捕获想要的异常操作
while True: num1 = input("num1 ") num2 = input("num2 ") try: num1 = int(num1) num2 = int(num2) ret = num1 + num2 print(ret) except ValueError as ex: #如果想对某种错误进行关注,就可以这样有针对性的进行错误捕获 print(ex) #这里就可以用日志来记录到文件中 except IndexError as ex: print(ex) except Exception as ex: #除了这两种错误,我就可以把其他的进行笼统的捕获 print(ex) #这里的错误就可以显示到屏幕上来。
看到上面的例子我们就知道了,为了程序的正常运行我们会在最下面用一个Exception这个万能的异常,上面是想捕捉的这些异常。
3、完整异常处理:
while True: num1 = input("num1 ") num2 = input("num2 ") try: num1 = int(num1) #正常的业务逻辑代码 num2 = int(num2) ret = num1 + num2 print(ret) except ValueError as ex: #如果想对某种错误进行关注,就可以这样有针对性的进行错误捕获 print(ex) #这里就可以用日志来记录到文件中 except IndexError as ex: print(ex) except Exception as ex: #除了这两种错误,我就可以把其他的进行笼统的捕获 print(ex) #这里的错误就可以显示到屏幕上来。 else: print("没有错就执行") finally: print("有没有错都执行")
4、主动触发异常
while True: num1 = input("num1 ") num2 = input("num2 ") try: raise Exception("错误") #这里可以随意定义异常的类型,定义什么类型的异常,下面就可以接受什么样的类型 print(123) #因为上面主动执行了异常,所以这里就不执行了 except ValueError as ex: #如果想对某种错误进行关注,就可以这样有针对性的进行错误捕获 print(ex,"value") except IndexError as ex: print(ex,"index") except Exception as ex: #上面raise的异常就被这里接受了 print(ex,"except")
5、断言
assert
使用方法
while True: num1 = input("num1 ") num2 = input("num2 ") try: assert int(num1) == int(num2) #如果这两个值相等,则执行print(123) print(123) #如果不相等,就直接报错 except AssertionError as ex: print(ex, "assert") else: print("没有错就执行") finally: print("有没有错都执行")
如果有个对象是启动某个程序的,想启动某些程序需要满足的条件: 当前这个程序应该是停止状态, 这个程序有个方法 class process: def status(self): ret = 查看当前程序的状态 (True/False) return ret def start(self) try: assert self.status() == False #在这里就相当于判断了状态,如果等于False,就满足启动条件,否则就报错了 则执行启动程序 except AssertionError as ex: #这里接受报错 print(ex, "assert") #并打印
from multiprocessing import pool b = pool.Pool b.join() def join(self): util.debug('joining pool') assert self._state in (CLOSE, TERMINATE) #能满足我这个条件就往下执行,否则就抛出个异常 self._worker_handler.join() self._task_handler.join() self._result_handler.join() for p in self._pool: p.join()