面向对象2
面向对象(进阶)
1,针对上一节作业需要补充的几点知识
├── daytest
│ ├── test.py
│ └── test.txt
└── test
└── t1.py
目录结果如上,在test.py中有一个类C1,根据类创建一个对象obj,然后把对象pickle到
test.txt中,在另外的一个目录下,如何把obj反序列化回来?思路要想反序列化回来必须导入类。
解答:
如果,test.py和t1.py在同一级目录下,直接导入类即可---> from test import C1。
如上这种情况,该怎么办,
sys.path.append(os.path.dirname(os.path.dirname(__file__))) # 先把父目录添加到环境变量中
from daytest.test import C1 #
r = os.path.join(os.path.dirname(os.path.dirname(__file__)), "daytest", "test.txt")
r = pickle.load(open(r, "rb"))
print(r.name, r.age)
一,多态(多种形态,或 多种类型)
python默认本身支持多态,java、C#默认是不支持多态的。
例如:
# JAVA或者C#中,在传参数的时候必须指定参数的类型,int,float等,
#而python本身,默认可以传多种类型。
1 def func(int, args) 2 print(args) 3 4 func(12) #正确 5 func("alex") #报错 6 7 8 但是如果:C#和JAVA也要支持多态,则必须借助继承来实现,如下: 9 class A: 10 def __init__(self): 11 pass 12 13 class B(A): 14 15 def __init__(self): 16 pass 17 18 class C(A): 19 def __init__(self): 20 pass 21 22 # args参数,必须是A类型,或者A的子类类型 23 def func(A, args): 24 print(args) 25 26 # obj = B() 27 # obj = C() 28 obj = A() 29 func(obj) 30 # 此时的func函数就可以支持多种类型
python的多态,也增加了看源码的难度,因为当源码中有函数时,你并不知道它是什么类型!
二,类成员之字段和方法
a, 普通字段和静态字段
1 class Foo: 2 CC = "中国" # 静态字段,保存在类中,可以用类或者对象访问,在代码加载时已经创建 3 # 强烈建议静态字段要用类进行访问,因为在java和c中都是用类访问。 4 5 def __init__(self, name): 6 self.name = name # 普通字段(也有人称为动态字段),保存在对象中 7 # 只能使用对象访问 8 9 def show(self): 10 pass 11 12 obj = Foo("河南") 13 print(obj.name) 14 15 r = Foo.CC # 用类访问 16 r1 = obj.CC # 用对象访问 17 print(r) 18 print(r1) 19 20 # 注意静态字段可以用del Foo.CC去删除 21 22 结果: 23 24 河南 25 中国 26 中国
总结:
静态字段,保存在类中,可以用类或者对象访问,在代码加载时已经创建。强烈建议用类访问。
普通字段,保存在对象中,只能使用对象访问,在代码加载时没有创建,因为代码加载时并没有创建类。
b, 静态方法和普通方法
1 class Foo: 2 CC = "中国" 3 4 def __init__(self, name): 5 self.name = name 6 7 def show(self): # 普通方法,方法属于类,由对象调用并执行 8 print(self.name) 9 10 @staticmethod 11 def f1(args1, args2): # 静态方法, 也属于类,由类来调用并执行 12 print(args1, args2) 13 14 def f2(self): 15 print("hello") 16 17 obj = Foo("河南") 18 print(obj.name) 19 obj.f1("hello", "world") # 由对象调用, 浪费内存。 20 21 Foo.f1("hello", "world") # 由类去调用,所以静态方法要用类去调用! 22 23 结果: 24 25 河南 26 hello world 27 hello world
总结:
# 对于不使用对象的方法(如f2方法)都可以改为,静态方法,这样就可以更加节省内存。
# 静态方法其实本质上就是函数,如果该函数跟Foo这个类没有任何的联系,完全可以写到类外面。
c, 类方法,本质也是一种特殊的静态方法
1 class Foo: 2 CC = "中国" 3 4 def __init__(self, name): 5 self.name = name 6 7 def show(self): # 普通方法,方法属于类,由对象调用并执行 8 print(self.name) 9 10 @staticmethod 11 def f1(a, b): # 静态方法, 也属于类,由类来调用并执行 12 print(a, b) 13 14 @classmethod # 类方法,本质也是一种静态方法,必须会有一个参数cls,在调用时不用传入参数, 15 def f2(cls): # 由Python自动传递 16 print(cls) # ----> 输出为:类名 <class '__main__.Foo'> 17 18 Foo.f2() 19 20 结果: 21 22 <class '__main__.Foo'> # 这个__main__,很好理解!
总结:
所有的方法都属于类:
1, 普通方法:至少有一个self, 由对象执行
2, 静态方法:任意参数, 由类执行(对象执行)
3, 类方法: 至少有一个cls, 由类执行(对象执行)
切记:不到万不得已,静态方法和类方法不能用对象执行。
三, 类成员之属性(不伦不类的东西,具有方法的定义形式,具有字段的访问形式)
1,类实现的简单的分页功能
1 class Paper: 2 3 def __init__(self, all_count): 4 self.all_count = all_count 5 6 @property 7 def all_paper(self): 8 a1, a2 = divmod(self.all_count, 10) 9 if a2 == 0: 10 return a1 11 else: 12 return a1 + 1 13 p = Paper(101) 14 # p.all_count 字段 15 # p.all_paper() 方法 16 ret = p.all_paper # 在没有@property之前,ret = p.all_paper(),即可获得结果 17 print(ret) # 加上@property之后,不加()就可以调用。
2, 属性的表达形式之一
1 class Paper: 2 3 def __init__(self, all_count): 4 self.all_count = all_count 5 6 @property 7 def all_paper(self): 8 a1, a2 = divmod(self.all_count, 10) 9 if a2 == 0: 10 return a1 11 else: 12 return a1 + 1 13 14 @all_paper.setter # -----------> 注意这里的装饰器的名字必须是上面的函数名 15 def all_paper(self, value): # -----------> 同样,注意理解,下面类似 16 print(value) 17 18 @all_paper.deleter 19 def all_paper(self): 20 print("all_paper") 21 22 p = Paper(101) 23 24 ret = p.all_paper # ---------> 执行对应的@property下面的方法 25 print(ret) 26 p.all_paper = 888 # ---------> 执行对应的@all_paper.setter下面的方法,并把888赋值给方法中的value 27 del p.all_paper # ---------> 执行对应的@all_paper.deleter下面的方法 28 29 30 结果: 31 11 32 888 33 all_paper
注意:这里的获取、修改、删除,只是执行了对应的方法,方法里面具体执行什么可以自己去定义。
而不是真正的删除,获取,修改。
3,属性的另外一种表达方式(比较常见,特别是在源码中特别常见!)
1 class Pager: 2 def __init__(self, name): 3 self.name = name 4 5 def f1(self): 6 return "hello world" 7 8 def f2(self, value): 9 print(value) 10 11 def f3(self): 12 print("del") 13 14 foo = property(fget=f1, fset=f2, fdel=f3) # fget,fset, fdel都是python定义好的,当函数名当作参数传递 15 16 p = Pager("tom") 17 result = p.foo # -------->只要是这样的书写格式就去执行f1方法 18 print(result) 19 20 p.foo = "LinTao" #--------->只要是这样的书写格式就去执行f2方法,并且把等号后面的值传递给f2的中的参数value 21 22 del p.foo #--------->只要是这样的书写格式就去执行f3方法 23 24 25 结果如下: 26 hello world 27 LinTao 28 del
四, 类成员之成员修饰符(顾名思义就是修饰成员的:字段,方法,属性)
在python中相对比较简单,而在java和C#里面有四种:公有的,私有的,一个程序集里面可用的,一个是受保护的,
在python中就有两个:
1, 公有(在内部,外部都能访问得到)
2, 私有(只能类本身成员内部可以访问)
字段
1,私有普通字段
1 class Foo: 2 def __init__(self, name): 3 self.__name = name # ------> 私有, 当在字段前面加两个下划线,字段就变成私有的字段,只能内部访问 4 5 def f1(self): 6 print(self.__name) # ------> 内部调用 7 8 9 class Bar(Foo): 10 def f2(self): 11 print(self.__name) 12 13 obj = Foo("tom") 14 obj.f1() #--------->在内部访问,能访问得到 15 print(obj.name) # --------> 在外部调用,会报错!!! 16 obj1 = Bar("lily") # -------> 通过外部访问, 不能访问,会报错!!! 17 obj1.f2()
2,私有静态字段
1 class Foo: 2 __CC = "hello world" 3 4 def __init__(self, name): 5 self.__name = name 6 7 @staticmethod 8 def f1(): 9 print(Foo.__CC) 10 11 # print(Foo.CC) # ------->在外部不能访问,会报错! 12 Foo.f1() # ------->在内部可以访问到
总结:方法和属性,同字段一样,私有的只能在内部访问。但是有一种特殊情况,如下:
1 class Foo: 2 def __init__(self, name): 3 self.name = name 4 5 def __f1(self, name, age): 6 self.name = name 7 print(name, age) 8 9 def f2(self): 10 Foo("tom").__f1("tom", 22) 11 12 13 obj = Foo("tom") 14 obj.f2() # ---------> 私有的方法f1,只能在内部进行访问。 15 # obj.Foo__f1("lily", 23)# ---------> 私有的方法f1,在外部访问会报错!!! 16 obj._Foo__f1("lily", 23) #----------> 如果强制想在外部访问,必须在类名的前面加一个下划线。
强烈建议:不到万不得已,不能这么去用!!!!!
五, 特殊成员
# __doc__ 注释用
# __module__ 表示当前操作的对象在哪个模块, 输出模块的位置
# __class__ 表示当前操作的对象的类是什么
举例:test.py 如下:
1 class C1: 2 def __init__(self): 3 pass 4 5 def f1(self): 6 pass 7 8 9 10 from dtest.test import C1 11 obj1 = C1() 12 print(obj1.__class__) 13 print(obj1.__module__) 14 15 结果如下: 16 17 <class 'dtest.test.C1'> 18 dtest.test
# __init__ 构造方法,创建对象的时候将会自动触发该方法。
# __del__ 析构方法,当对象的内存被释放时,自动触发执行。
# 注意:此方法无需定义,因为python是一门高级语言,程序员在使用时无需关心内存的分配和释放,
# 因为此工作都是交给python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动
# 触发执行的。
# __call__ 对象后面加括号,触发执行
# 注意:构造方法的执行是由创建对象触发的,即对象 = 类名();而对于__call__方法的执行是由对象
# 后加括号触发的,即:对象() 或者 类()()
1 class Foo: 2 def __init__(self): 3 pass 4 5 def __call__(self, *args, **kwargs): 6 print("执行call方法!") 7 8 obj = Foo() 9 obj() 10 11 结果如下: 12 执行call方法!
# __str__ 如果定义了该方法,那么在打印 对象 时,默认输出该对象的返回值!
1 class Foo: 2 def __init__(self, name, age): 3 self.name = name 4 self.age = age 5 6 def __str__(self): 7 return "{} {}".format(self.name, self.age) 8 9 obj = Foo("tom", "21") 10 print(obj) 11 12 结果如下: 13 tom 21
# __add__ 当两个对象相加时,会自动调用__add__,里面的方法,获取返回结果!
1 class Foo: 2 def __init__(self, name, age): 3 self.name = name 4 self.age = age 5 6 def __add__(self, other): 7 return self.name, other.age # 我们去obj中的name和obj1中的age 8 9 obj = Foo("tom", "21") 10 obj1 = Foo("lily", "72") 11 ret = obj + obj1 12 print(ret) 13 14 结果如下: 15 16 ('tom', '72')
# __dict__ 获取对象中封装的所有的数据并放入字典中。非常重要!!!
# 当然,该方法也可以获取类中封装的数据,并放入字典。这个用的少一些
class Foo: def __init__(self, name, age): self.name = name self.age = age def f1(self): pass def f2(self): pass obj = Foo("tom", "21") print(obj.__dict__) print(Foo.__dict__) 结果如下: {'age': '21', 'name': 'tom'} # 获取对象obj中封装的数据 {'__doc__': None, '__init__': <function Foo.__init__ at 0x000000000091AEA0>, '__dict__': <attribute '__dict__' of 'Foo' objects>, '__weakref__': <attribute '__weakref__' of 'Foo' objects>, 'f1': <function Foo.f1 at 0x000000000091AF28>, '__module__': '__main__', 'f2': <function Foo.f2 at 0x0000000000926048>}
下面三种重要的方法非常重要,在web框架中自定义session框架会用到这个!!!
# __setitem__
# __getitem__
# __delitem__
1 class Foo: 2 def __init__(self, name, age): 3 self.name = name 4 self.age = age 5 6 def __getitem__(self, item): 7 return 123, item 8 9 def __setitem__(self, key, value): 10 print(key, value) 11 12 def __delitem__(self, key): 13 print(key) 14 15 obj = Foo("tom", "21") 16 # 语法对应关系 17 ret = obj["hello"] # 只要是:对象["xxx"],这种格式,就会执行__getitem__方法,并把"xxx"传递给item 18 print(ret) 19 20 obj["k1"] = 88 # 只要是:对象["xx"] = xxx,这种格式,就会执行__setitem__方法,并把"xx"传递给key,"xxx"传递给value 21 22 del obj["ok"] #只要是:del 对象["xxx"],这种格式,就会执行__delitem__方法,并把"xxx"传递给
还有一种特殊的切片的方式的应用,和上面类似
1 class Foo: 2 def __init__(self, name, age): 3 self.name = name 4 self.age = age 5 6 def __getitem__(self, item): 7 print(item, type(item)) # 类型是切片 8 print(item.start, item.stop, item.step) # 包括起始,步长 9 10 def __setitem__(self, key, value): 11 print(key, value) 12 13 def __delitem__(self, key): 14 print(key) 15 16 obj = Foo("tom", "21") 17 18 obj[1:5:2] 19 obj[1:5:2] = 888 20 del obj[1:5:2] 21 22 23 结果如下: 24 25 slice(1, 5, 2) <class 'slice'> 26 1 5 2 27 slice(1, 5, 2) 888 28 slice(1, 5, 2)
# __iter__ 当用for循环一个对象的时候,会去执行__iter__方法,然后拿到返回值,再进行迭代。list,字典,等之所以
能进行迭代就是因为内部使用了__iter__方法
1 class C1: 2 def __init__(self): 3 pass 4 5 def __iter__(self): 6 yield 1 7 yield 2 8 9 obj = C1() 10 for i in obj: 11 print(i) 12 13 14 结果如下: 15 16 1 17 2
# __new__ 和 __metaclass__ 可以解释,是由谁创建类的
1,当你使用class关键字时,python解释器自动创建了这个对象。
2,但是就和大多数事情一样,python仍然提供给你了手动处理的方法,那就是内置函数type。
type是python中通常的元类。元类就是在python背后创建所有类的元类,创建类的类。
语法格式如下:
type(类名, 父类的元组(针对继承的情况,可以为空),包含属性的字典(名称和值))
第一种方式:(常见)
class Foo(object): def __init__(self, name): self.name = name def f1(self): print("hello world") f = Foo("tom") f.f1() print(type(Foo)) # <class 'type'> Foo来自type,说明类是由type创建的
第二种方式:(特殊)
例1.
def func(self): print("hello world") Foo = type('Foo', (), {'f1': func}) #type第一个参数:类名 #type第二个参数:当前类的基类 #type第三个参数:类的成员 obj = Foo() obj.f1() print(type(Foo)) # <class 'type'> Foo来自type,说明类是由type创建的
例2.
def func(self): print(self.name) def __init__(self, name, age): self.name = name self.age = age Foo = type('Foo', (object, ), {'f1': func, '__init__': __init__}) obj = Foo("tom", 21) obj.f1() print(type(obj)) print(type(Foo))
执行结果: tom <class 'type'> <class '__main__.Foo'>
在python中:一切皆对象!类同样也是对象!
通过以上:我们可以看出obj对象是由类Foo实例化过来的,Foo类是通过type类产生的,
到底type是如何创建类的,类又是如何产生对象的呢?
1,创建类是通过元类type来实现, 其中类中有一个___metaclass___属性(表示该类是由谁实例化创建的)
2,类实例化产生对象,则和__new__方法关系密切!
__metaclass__是什么?
创建类的过程:
1, 比如当你写上class Foo(object)时,类对象Foo并没有在内存中创建Foo,python会在类的定义中找到__metaclass__属性。
如果找到了,python就会用它来创建类对象,如果没有找到,就会去父类中寻找__metaclass__属性,如果都找不到就会在模块
层次去寻找__metaclass__,并尝试同样的操作。如果还是找不到__metaclass__,python就会用内置的type来创建这个类对象。
到底__metaclass中放置什么代码呢?答案是可以创建一个类的代码,什么又可以创建一个类呢?!type或者子类化type的东西。
type创建类的表达式如上。
元类type的用途有那些呢?
元类的主要用途是创建API。一个典型的例子是Django ORM。元类的主要目的就是为了当创建类时能够自动地改变类。通常,你会为API
做这样的事情,你希望可以创建符合当前上下文的类。还可以轻易的做到 1) 拦截类的创建 2) 修改类 3) 返回修改之后的类
__new__是什么?
在 Python 中存在于类里面的构造方法 __init__() 负责将类的实例化,而在 __init__() 启动之前,__new__() 决定是否要使用该
__init__() 方法,因为__new__() 可以调用其他类的构造方法或者直接返回别的对象来作为本类的实例。
通常来说,新式类开始实例化时,__new__()方法会返回cls(cls指代当前类)的实例,然后该类的__init__()方法作为构造方法会接收
这个实例(即self)作为自己的第一个参数,然后依次传入__new__()方法中接收的位置参数和命名参数。
事实上如果(新式)类中没有重写__new__()方法,即在定义新式类时没有重新定义__new__()时,Python默认是调用该类的直接父类的
__new__()方法来构造该类的实例,如果该类的父类也没有重写__new__(),那么将一直按此规矩追溯至object的__new__()方法,因为
object是所有新式类的基类。
类的创建过程以及如何通过类来创建对象的class MyType(type):
class MyType(type) def __init__(self, what, bases=None, dict=None): # print("***MyType.__init__") super(MyType, self).__init__(what, bases, dict) def __call__(self, *args, **kwargs): # print("***MyType.__call__") obj = self.__new__(self, *args, **kwargs) self.__init__(obj) class Foo(object, metaclass=MyType): # __metaclass__ = MyType def __init__(self): # print("***Foo.__init__") pass def __new__(cls, *args, **kwargs): # print("***Foo.__new__") return object.__new__(cls, *args, **kwargs) # 第一阶段:解释器从上到下执行代码创建Foo类 # 第二阶段:通过Foo类创建obj对象 obj = Foo()
首先会加载class MyType 和 Class Foo(记住此时并没有创建Foo),加载完之后由于发现了metaclass,则会直接执行MyType类中的__init__方法,此时就是在用元类type创建类Foo,此时super(MyType, self).__init__(what, bases, dict)中的self即为Foo,此时就已经创建了Foo类
第二阶段:通过Foo类创建obj对象
obj = Foo(),此时开始执行这一行代码,Foo为元类创建的类对象(),相当于类()(),于是就开始调用Mytype中__call__方法,__call__方法中才是创建类的开始。
obj = self.__new__(self, *args, **kwargs) 注意此时self为Foo,所以开始调用了Foo类中的__new__方法,其实类的真正实例化是从这一步开始的。
self.__init__(obj) # 执行类的初始化,把self传进去。
注意事项:以上是在python3环境下实现的,python2中写法会有所区别,详见博客 http://www.cnblogs.com/wupeiqi/p/4766801.html
六, 面向对象其他知识点
1,isinstance,查看对象是否是由某个类的实例
1 class C1: 2 pass 3 4 obj = C1() 5 6 r = isinstance(obj, C1) 7 print(r) 8 9 结果如下: 10 True
# 注意如果,C1继承了C2,那么r = isinstance(obj, C2)也同样会返回True,不仅是子类的实例
#也是父类的实例
2,issubclass,查看某个类是否是其他类的子类
1 class C1: 2 pass 3 4 5 class C2(C1): 6 pass 7 8 r = issubclass(C2, C1) 9 print(r) 10 11 结果如下: 12 True
3,执行父类的方法(这是修改源码的一种非常重要的思路!!!!!!)
a, 执行父类的第一种方法
正常情况下,Bat类在继承Foo类以后,仍然会先执行自己的f1方法
但是加上super(Bat,self).f1()之后则会主动去执行Foo的f1方法。
1 class Foo: 2 def __init__(self, name): 3 self.name = name 4 5 def f1(self): 6 print("Foo.f1") 7 8 9 class Bat(Foo): 10 def f1(self): 11 # 主动执行父类的f1()方法 12 super(Bat, self).f1() 13 print("Bat.f1") 14 15 obj = Bat("tom") 16 obj.f1()
b, 执行父类的第二种方法,但是python3.0以后不建议这么去用
1 class Foo: 2 def __init__(self, name): 3 self.name = name 4 5 def f1(self): 6 print("Foo.f1") 7 8 9 class Bat(Foo): 10 def f1(self): 11 # 主动执行父类的f1()方法 12 Foo.f1(self) # -----------> 注意:如果父类中有参数,还得办法把参数传进去 13 print("Bat.f1") 14 15 obj = Bat("tom") 16 obj.f1()
4,实例之自定义有序字典
1 class MyDict(dict): # 创建自定义字典,继承字典 2 def __init__(self): 3 self.li = [] # 创建了一个空列表 4 super(MyDict, self).__init__() # 不能改变原来的内容 5 6 def __setitem__(self, key, value): 7 self.li.append(key) # 每增加一个值即把key添加到列表中 8 super(MyDict, self).__setitem__(key, value) # 不能改变原来的内容 9 10 def __str__(self): # 打印对象执行此方法 11 temp_list = [] 12 for key in self.li: 13 value = self.get(key) # 执行父类的get方法,取出value的值 14 temp_list.append("'%s': %s" % (key, value,)) 15 temp_str = "{" + ",".join(temp_list) + "}" 16 return temp_str 17 18 19 obj = MyDict() 20 obj["k1"] = 123 21 obj["k2"] = 456 22 print(obj) 23 24 结果如下: 25 26 {'k1': 123,'k2': 456}
七,面向对象之单例模式
# 设计模式(20多种设计模式)之单例模式:只有一个实例
# 设计模式是就为了使代码具有更好的扩展性
# 单例模式例如:数据库连接池(即不管有多少人访问,只有一个连接池,不可能存在大量的连接池。)
1 class Foo: 2 """ 3 构造单例模式 4 """ 5 instance = None 6 7 def __init__(self, name): 8 self.name = name 9 10 @classmethod 11 def get_instance(cls): 12 if cls.instance: 13 return cls.instance 14 else: 15 obj = cls("alex") 16 cls.instance = obj 17 return obj 18 19 obj1 = Foo.get_instance() 20 print(obj1) 21 obj2 = Foo.get_instance() 22 print(obj2) 23 24 结果如下:内存地址是一样的。 25 <__main__.Foo object at 0x0000000000922470> 26 <__main__.Foo object at 0x0000000000922470>
八,异常处理
1,异常处理的种类(python中的异常种类非常多,每个异常专门用于处理某一项异常!!!)
a, 常见的异常处理类型
AttributeError 试图访问一个对象没有的树形,比如foo.x,但是foo没有属性x
IOError 输入/输出异常;基本上是无法打开文件
ImportError 无法引入模块或包;基本上是路径问题或名称错误
IndentationError 语法错误(的子类) ;代码没有正确对齐
IndexError 下标索引超出序列边界,比如当x只有三个元素,却试图访问x[5]
KeyError 试图访问字典里不存在的键
KeyboardInterrupt Ctrl+C被按下
NameError 使用一个还未被赋予对象的变量
SyntaxError Python代码非法,代码不能编译(个人认为这是语法错误,写错了)
TypeError 传入对象类型与要求的不符合
UnboundLocalError 试图访问一个还未被设置的局部变量,基本上是由于另有一个同名的全局变量,
导致你以为正在访问它
ValueError 传入一个调用者不期望的值,即使值的类型是正确的
b, 万能的异常处理类型Exception
注意:对于特殊处理或提醒的异常需要先定义,最后定义Exception来确保程序正常运行
1 s = input("age:") 2 try: # 正确则执行try块里面的内容 3 int(s) 4 print(s) 5 except ValueError as ex: # python会一级一级的向下检查,只要符合条件就不再向下执行 6 print(ex) 7 except IndexError as ex: 8 print(ex) 9 except Exception, e: 10 print '错误'
2,异常的其他结构(一定要注意执行的顺序)
1 try: 2 # 主代码块 3 pass 4 except KeyError,e: 5 # 异常时,执行该块 6 pass 7 else: 8 # 主代码块执行完,执行该块 9 pass 10 finally: 11 # 无论异常与否,最终执行该块 12 pass
3,主动触发异常
1 s = input("age:") 2 try: 3 raise Exception("主动错误一下!") # 创建一个Exception对象,此处也可改为ValueError,想抛什么抛什么 4 int(s) 5 print(s) 6 except ValueError as ex: 7 print(ex) 8 except IndexError as ex: 9 print(ex) 10 except Exception as tx: # self.message = "主动错误一下!" 11 print(tx) # __str__, return self.message 12 else: 13 pass 14 finally: 15 pass
4,自定义异常
1 class MyException(Exception): 2 def __init__(self, msg): 3 self.message = msg 4 5 def __str__(self): 6 return self.message 7 8 try: 9 raise MyException("我的异常处理") 10 except MyException as e: 11 print(e) 12 13 结果如下: 14 我的异常处理
5,断言(类似于if...pass... + raise主动抛出异常),条件通过才能向下执行。
1 assert 1 == 1 2 print("ok")