Python 之 面向对象编程
一、概述
1.1 与面向过程的对比
1.1.1 面向过程
- 概念:核心是“过程”二字,就是将你所需要开发的事物按照过程来编写,就像流水线一般,将每一项工艺怎么弄的定义成一个函数,就是面向过程编程。
- 优点:将一些大问题化成一系列小问题,将其简单化。
- 缺点:可拓展性差,即其只能用于特定的场合。
- 适用场景:用于不会常改变的场合,著名的例子有Linux內核,git,以及Apache HTTP Server等。
1.1.2 面向对象
- 概念:核心是“对象”二字,将过程所对应的函数统一成对象,在python,万物皆对象。
- 优点:可拓展性好。
- 缺点:编程的复杂度远高于面向过程。
- 适用场景:应用于需求经常变化的软件,集中在用户层,互联网应用,企业内部软件,游戏等。
二、类与对象
2.1 类
- 概念:就是一系列对象相似的特征与技能的结合
![]()
- 查看类的名称空间:
- 类名.__dict__ : 以字典的形式保存的
- 四个针对类的属性方法的操作(增删改查)
- 增:类名.属性名=值 如Foo.name=‘jiangnan’
- 删:del 类名.属性名 如 del Foo.school
- 改:类名.属性名=修改后的值 如Foo.school=‘jiangnan’
- 查:类名.属性名 如Foo.school
2.2 对象
- 创建的格式:对象名=类名(独有的属性(即__init__(属性名)))
- 在类中的函数属性是绑定给对象使用的,绑定不同的对象就有不同的绑定方法,对象调用方法时,会将对象本身作为第一个传入,即作为self传入。
三、三大特性
面向对象的三大特性是指:继承、多态和封装。
3.1 继承
继承指的是类与类之间的关系,一个类可以继承一个或多个类,父类可以成为基类或超类。
3.1.1 查看继承:
语法:类名.__bases__
3.1.2 属性查找:
先在自己类中查找,没有去父类中查找,以此类推。

3.1.3 继承实现的原理
合并所有父类的mro列表(类名.__mro__)并遵循如下三条准则:
- 子类会先于父类被检测
- 多个父类会根据他们在列表中顺序被检查
- 如果对下一个类存在两个合法的选择,选择第一个父类
在python2中,有两种类:
-
- 新式类:继承object的类,以及他的子类
- 经典类:没有继承object的类,以及他的子类
在python3中,只有新式类
查找有两个方式:深度优先(新式类)、广度优先(经典类)
经典类 新式类(python3)

在子类中重调父类中的属性,有两种方法:
- 指名道姓的使用(不依赖继承):父类名.属性名()
- 使用super:super().属性名()
简而言之,super()就是mro列表下一个查找的(广度优先)
3.1.4. super原理
1 def super(cls,inst): 2 mro = inst.__class__.mro() 3 return mro[mro.index(cls)+1]
其中,cls代表类,inst代表实例,上面的代码做了两件事:
- 获取inst的mro列表
- 查找cls在当前mro列表中的index,并返回它的下一个类,即mro[index+1]
当你使用super(cls,inst)时,python会在inst的mro列表中搜索cls的下一个类
现在举出一个例子:
class Base(object): def __init__(self): print("enter Base") print("leave Base") class A(Base): def __init__(self): print("enter A") super(A, self).__init__() print("leave A") class B(Base): def __init__(self): print("enter B") super(B, self).__init__() print("leave B") class C(A, B): def __init__(self): print("enter C") super(C, self).__init__() print("leave C") c=C() print(C.__mro__)
对于这类问题,我们先要知晓其mro列表中的顺序,对于本例子,mro列表:C-->A-->B-->object
因此,执行这个程序时,先执行的是C类,即先打印:enter C ,然后遇到super,即在mro中进入下一个类中,即A,此刻在打印出 enter B,此后因此打印。当打印到object类时,最后反向返回,此处类似于递归。
此处答案应为:
enter C
enter A
enter B
enter Base
leave Base
leave B
leave A
leave C
3.1.5 组合
- 定义
就是在一个类中以另外一个类的对象作为数据属性。即“什么”有“什么” - 列子
View Codeclass Person: school='luffycity' def __init__(self,name,age,sex): self.name=name self.age=age self.sex=sex class Teacher(Person): def __init__(self,name,age,sex,level,salary): super().__init__(name,age,sex) self.level=level self.salary=salary def teach(self): print('%s is teaching'%self.name) class Student(Person): def __init__(self,name,age,sex,class_time): super().__init__(name, age, sex) self.class_time=class_time def learn(self): print('%s is learning'%self.name) class Course: def __init__(self,course_name,course_price,course_period): self.course_name=course_name self.course_price=course_price self.course_period=course_period def tell_info(self): print('课程名<%s>课程价钱<%s>课程周期<%s>'%(self.course_name,self.course_price,self.course_period))
t1=Teacher('alex',18,'male',10,3000) python=Course('python',3000,'3mons') t1.course=python print(t1.course.course_name)#python t1.course.tell_info()#课程名<python>课程价钱<3000>课程周期<3mons>
3. 当类之间有显著不同时,并且较小的类是较大的类所需要的组件时,使用组合
3.1.6 抽象类(了解)
- 定义
与java一样,python也有抽象类的概念,但是同样需要借助模块实现,抽象类是一个特殊的类,他的特殊之处在于只能被继承,不能被实例化。 - 原因
抽象类是从一堆类中抽象出来的,内容包括数据属性和函数属性。
View Codeimport abc class Animals(metaclass=abc.ABCMeta):#抽象类,只能被继承,不能被实例化 all_type='animals' @abc.abstractmethod def run(self): pass @abc.abstractmethod def eat(self): pass class People(Animals): def run(self): print('1') def eat(self): print('e1') class dog(Animals): def run(self): print('2') def eat(self): print('e2') p1=People() p1.run()
3.2 多态
- 定义
就是指一类事物有多种形态,如:
动物有多种形态:人、狗等都有走路说话吃饭等
因此,多态就是指不考虑实例类型的情况下使用实例。 - abc模块的作用
Python本身不提供抽象类和接口机制,要想实现抽象类,可以借助abc模块。ABC是Abstract Base Class的缩写。 - abc模块中的类和函数
abc.ABCMeta
这是用来生成抽象基础类的元类。由它生成的类可以被直接继承。
abc.abstractmethod(function) - 实例
#多态:同一种类型的多种形态 import abc class Animal(metaclass=abc.ABCMeta): #同一类事物:动物 @abc.abstractmethod def talk(self): print('haha') class People(Animal): #动物的形态之一:人 def talk(self): print('say hello') class Dog(Animal): #动物的形态之二:狗 def talk(self): super().talk() class Pig(Animal): #动物的形态之三:猪 def talk(self): print('say aoao')
调用时:
#多态性:在不考虑实例类型的情况下使用实例 peo1=People() dog1=Dog() pig1=Pig() peo1.talk()#say hello dog1.talk()#haha pig1.talk()#say aoao
我们可以定义一个统一的接口来完成
def func(animal): animal.talk() func(peo1)#say hello
3.3 封装
3.3.1 隐藏
class A: __x=1#_A__x=1 def __init__(self,name): self.__name=name#self._A__name=name def __foo(self):#_A__foo(self) print('run foo') def bar(self): self.__foo()#self._A__foo() print('from bar') def ww(self): print(self.__x) a=A('wei')##{'_A__name': 'wei'} print(a.__dict__)##'__module__': '__main__', '_A__x': 1, '__init__': <function A.__init__ at 0x000001D26C0BB950>, '_A__foo': <function A.__foo at 0x000001D26C0BB9D8>, 'bar': <function A.bar at 0x000001D26C0BBA60>, '__dict__':。。。} print(A.__dict__)##1 print(a._A__x)##run foo a.bar()##from bar a.ww()##1
特点:
1、在类外部无法直接obj.__AttrName访问
2、在类内部可以直接obj.__AttrName访问
3、子类无法覆盖父类__开头的属性
如:
###常规 class A: def fa(self): print('from A') def test(self): self.fa() class B(A): def fa(self): print('from B') b=B() b.test() ###结果:from B——————》覆盖了,调用的是自己类中的 #使用隐藏方式 class A: def __fa(self):#_A__fa print('from A') def test(self): self.__fa()#self._A__fa class B(A): def __fa(self):#_B__fa print('from B') b=B() b.test() ###结果:from A ——————》没有覆盖,调用的还是父类的
3.3.2 封装
- 封装数据属性:明确区分内外,控制外部对隐藏属性的操作行为
View Codeclass People: def __init__(self,name,age): self.__name=name self.__age=age def tell_info(self): print('name:%s;age:%s'%(self.__name,self.__age)) def set_info(self,name,age): if not isinstance(name,str): print('名字必须是字符串') return if not isinstance(age,int): print('年龄必须是数字类型') return self.__name=name self.__age=age p=People('zhangsan',18) p.tell_info() p.set_info('alex','20') p.tell_info() p.set_info('alex1',30) p.tell_info()
输出的结果为:
name:zhangsan;age:18 年龄必须是数字类型 name:zhangsan;age:18 name:alex1;age:30
- 封装方法:为了隔离复杂度,即只显示我们的功能,而隐藏取得该功能的函数
View Code#取款是功能,而这个功能有很多功能组成:插卡、密码认证、输入金额、打印账单、取钱 #对使用者来说,只需要知道取款这个功能即可,其余功能都可以隐藏起来,很明显这么做,隔离了复杂度,同时也提升了安全性 class ATM: def __card(self): print('插卡') def __auth(self): print('用户认证') def __input(self): print('输入取款金额') def __print_bill(self): print('打印账单') def __take_money(self): print('取款') def withdraw(self): self.__card() self.__auth() self.__input() self.__print_bill() self.__take_money() a=ATM() a.withdraw()
四、反射
定义:通过字符串映射到对象的属性
python中反射功能有4个内置函数提供:hasattr、getattr、setattr、delattr,对应的含义为:检测是否含有某属性、获取该属性、设置属性、删除属性
- hasattr(object,name)
含义:通过字符串的形式去某个模块中判断东西是否存在
具体:判断一个对象里面是否有name属性或者name方法,返回BOOL值,有name特性返回True,否则返回False。 - getattr(object,name[,default])
含义:通过字符串的形式去某个模块中获取东西
具体:获取对象object的属性或者方法,如果存在,打印出来,如果不存在,打印出默认值
注:如果返回的对象的方法,返回的是方法的内存地址,如果需要运行这个方法,在后面加个括号。 - setattr(object,name,values)
含义:通过字符串的形式去某个模块中设置东西
具体:给对象的属性赋值,若属性不存在,先创建再赋值 - delattr(object,name)
含义:通过字符串的形式去某个模块中删除东西
具体:删除属性
例子:
class People: def __init__(self,name,age,sex): self.name=name self.age=age self.sex=sex def talk(self): print('%s is talking'%self.name) p=People('alex',18,'male') #检测是否含有某属性 print(hasattr(p,'name'))#-------------->True #获取属性 print(getattr(p,'name'))#-------------->alex #设置属性 print(setattr(p,'sex','flmale'))#-------------->None print(p.sex)#-------------->flmale #删除属性 print(p.__dict__)#-------------->{'name': 'alex', 'age': 18, 'sex': 'flmale'} delattr(p,'name')#--------------> print(p.__dict__)#-------------->{'age': 18, 'sex': 'flmale'}
反射一般用于:在类中,通过输入的字符串来调用类中不同属性或者方法,如下面这个例子:
class Service: def run(self): while True: inp=input('>>: ').strip() #cmd='get a.txt' cmds=inp.split() #cmds=['get','a.txt'] if hasattr(self,cmds[0]): func=getattr(self,cmds[0]) func(cmds) def get(self,cmds): print('get.......',cmds) def put(self,cmds): print('put.......',cmds) obj=Service() obj.run()
结果为:get....... ['get', 'a.txt']
五、绑定方法与非绑定方法
在类内部定义方法,主要分为两类:绑定方法和非绑定方法
5.1 绑定方法
- 定义:
绑定给谁就应该由谁来调用,谁来调用就会把调用者当做第一个参数自动传入 - 分类:
主要分为两类:
绑定到对象的方法:在类定义中没有被任何修饰器修饰的方法
绑定到类的方法:在类定义中被classmethod修饰的方法
5.2 非绑定方法
- 定义:
没有自动传值这么一说,就类中定义的一个普通函数,对象和类都可以使用,不与类对象绑定。
5.3 实例
class Foo: def __init__(self,name): self.name=name def tell(self):#绑定到对象的方法 print('名字是%s' %self.name) @classmethod def func(cls): #绑定到类的方法#cls=Foo print(cls) @staticmethod def func1(x,y):#非绑定方法 print(x+y) f=Foo('alex') print(Foo.tell)#<function Foo.tell at 0x000002A70F4AB9D8> print(f.tell)#<bound method Foo.tell of <__main__.Foo object at 0x0000013C295F0518>> print(Foo.func)#<bound method Foo.func of <class '__main__.Foo'>> print(f.func)#<bound method Foo.func of <class '__main__.Foo'>> print(Foo.func1)#<function Foo.func1 at 0x0000029E1342BAE8> print(f.func1)#<function Foo.func1 at 0x0000029E1342BAE8>
六、属性方法
属性方法就是通过@property把一个方法变成一个静态属性
1 class People: 2 def __init__(self,name,weight,height): 3 self.name=name 4 self.weight=weight 5 self.height=height 6 @property 7 def bmi(self): 8 print(self.weight / (self.height ** 2)) 9 10 p=People('weimin',63.5,1.70)
当调用时,使用
p.bmi()
就会报错,报错如下
1 Traceback (most recent call last): 2 File "C:/Users/。。。/Desktop/python/oldboypython/day5/19property.py", line 27, in <module> 3 p.bmi() 4 TypeError: 'float' object is not callable
因此,正确调用就是不加括号,就行静态属性一样调用即可。
p.bmi
那么把一个方法变成静态属性有什么作用呢?当客户需要对一个参数进行修改时,我们可以限制该参数的格式等,调用@property.setter来进行设置参数的值,@property.deleter进行删除,例子如下:
1 class People: 2 def __init__(self,name): 3 self.__name=name 4 5 @property 6 def name(self): 7 print('getter') 8 return self.__name 9 10 @name.setter 11 def name(self,val): 12 print('setter',val) 13 if not isinstance(val,str): 14 print('名字必须是字符串类型') 15 return 16 self.__name=val 17 18 @name.deleter 19 def name(self): 20 print('deleter') 21 print('不允许删除') 22 23 p=People('alex') 24 p.name="ALEX"######-------> setter ALEX 25 p.name=123#######-------> setter 123;名字必须是字符串类型 26 del p.name######-------> deleter;不允许删除
七、内置函数
在这里要注意的是,内置函数与私有成员是有区别的,内置函数是前后都有两个字符的下划线,而私有成员只有前两个字符是下划线,
且私有成员与公有成员的不同点在于:
- 私有成员只能在类中调用,当然也可以在类外调用,格式为对象.__类__属性名
- 公有成员在任何地方均可访问
内置函数:
1、item系列(__getitem__/__setitem__/__delitem__)
其实就是在类中,将之前用调用方法的方式变成调用字典的方式。上述的三个函数分别表示为:获取、设置、删除数据。
1 class Foo: #Dict 2 def __init__(self,name): 3 self.name=name 4 5 def __getitem__(self, item): #item='namexxx' 6 print('getitem...',item) 7 return self.__dict__.get(item)#返回value 8 9 def __setitem__(self, key, value): 10 print('setitem...',key,value) 11 self.__dict__[key]=value#设置了key-value 12 13 def __delitem__(self, key): 14 print('delitem...',key) 15 del self.__dict__[key] 16 17 obj=Foo('egon') 18 #获取属性 19 print(obj['name'])#相当于print(obj.name)------->egon 20 #设置属性 21 obj['sex']='male'#调用__setitem__(self, key, value)函数 22 print(obj.__dict__)#------->{'name': 'egon', 'sex': 'male'} 23 #删除属性 24 del obj['sex']#调用__delitem__(self, key)函数, 25 print(obj.__dict__)#------->{'name': 'egon'}
2、__init__、__call__、__new__
对于__init__:通过类创建对象之后,自动触发执行。
对于__call__:对象后面加括号,触发执行
1 class Foo: 2 3 def __init__(self): 4 print('__init__') 5 6 def __call__(self, *args, **kwargs): 7 print('__call__') 8 9 obj = Foo() # 执行 __init__------>__init__ 10 obj() # 执行 __call__------>__call__
对于__new__:创建这个类对象的时候执行。
3、 __doc__
查看类的描述信息。
1 class Foo: 2 '''描述类信息,看看''' 3 def __init__(self): 4 print('__init__') 5 def __call__(self, *args, **kwargs): 6 print('__call__') 7 8 print(Foo.__doc__)#-------->'描述类信息,看看'
4、 __module__、__class__
__module__ 表示当前操作的对象在哪个模块
__class__ 表示当前操作的对象的类是什么
1 class C: 2 def __init__(self): 3 self.name='xiaozhupeiqi'
1 import os,sys 2 sys.path.append(os.path.dirname(__file__)) 3 import CC 4 obj=CC.C() 5 print(obj.__module__)#------->CC 6 print(obj.__class__)#-------><class 'CC.C'>
5、__str__、__repr__
改变对象的字符串显示__str__,__repr__
__str__ \__repr__ :在打印对象的时候执行,将返回的结果转成字符串格式打印出来
1 class People: 2 def __init__(self,name,age): 3 self.name=name 4 self.age=age 5 6 def __str__(self): 7 return 'Info(%s,%s)' % (self.name, self.age) 8 9 obj=People('zhu',18) 10 print(obj)
6、__del__
析构方法时,当对象在内存中被释放时,自动触发执行。在python中一般不需要定义。
比如:
f=open()-------->包括两部分:应用程序、操作系统(打开文件)
f.close()--------->回收操作系统的资源
但此时,f并没有被回收
7、isinstance(obj,cls)、issubclass(sub,super)
isinstance(obj,cls)判断是否obj是否是类cls的对象
1 class Foo(object): 2 pass 3 obj = Foo() 4 isinstance(obj, Foo)#------>True
issubclass(sub,super)判断类sub是否是类super的子类
1 class Foo(object): 2 pass 3 class Bar(Foo): 4 pass 5 issubclass(Bar, Foo)#------->True
八、元类
之前,我们一直说,python中一切皆对象,因此,类也是对象,因此,类的类型为type,称为type。
当使用type创建类的时候,有以下形式:
type(类名,父类的元组(可以为空),属性的字典)
例子:
1 def printInfo(self): 2 print("%s is %d years old" %(self.name, self.age)) 3 4 S = type("Student", (object, ), {"name": "Wilber", "age": 28, "printStudentInfo": printInfo}) 5 6 print(type(S))#-------->type 7 s=S() 8 print(type(s))#--------->Student 9 s.printStudentInfo()#--->Wilber is 28 years old
当需要自定义一个类时,我们可以设置"metaclass"属性。
就是,先定义metaclass,就可以创建类,最后创建实例。
例子:
1 class ListMetaclass(type): 2 def __new__(cls, name, bases, attrs): 3 attrs['add'] = lambda self, value: self.append(value) 4 return type.__new__(cls, name, bases, attrs) 5 6 class MyList(list, metaclass=ListMetaclass): 7 pass 8 9 L = MyList() 10 L.add(1) 11 print(L)#------>[1]
当我们传入关键字参数metaclass时,它指示Python解释器在创建MyList时,要通过ListMetaclass.__new__()来创建,在此,我们可以修改类的定义,比如,加上新的方法,然后,返回修改后的定义。
1 class Mymeta(type): 2 def __init__(self,class_name,class_bases,class_dir): 3 if not class_name.istitle(): 4 raise TypeError('类名的首字母必须大写') 5 6 if '__doc__' not in class_dir or not class_dir['__doc__'].strip(): 7 raise TypeError('必须有注释,且注释不能为空') 8 super().__init__(class_name,class_bases,class_dir) 9 10 class Chinese(object,metaclass=Mymeta):#Chinese=type(...) 11 ''' 12 中国人的类 13 ''' 14 country='China' 15 def __init__(self,name,age): 16 self.name=name 17 self.age=age 18 19 def talk(self): 20 print('%s is talking'%self.name) 21 22 23 # Chinese=Mymeta(class_name,class_bases,class_dir) 24 25 print(Chinese.__dict__)#---->{'__module__': '__main__', '__doc__': '\n 中国人的类\n ', 'country': 'China', '__init__': <function Chinese.__init__ at 0x0000022F8BE8A9D8>, 'talk': <function Chinese.talk at 0x0000022F8BE8AA60>, '__dict__': <attribute '__dict__' of 'Chinese' objects>, '__weakref__': <attribute '__weakref__' of 'Chinese' objects>} 26 c=Chinese('xiaoming',18)
1 class Mymeta(type): 2 def __init__(self,class_name,class_bases,class_dir): 3 if not class_name.istitle(): 4 raise TypeError('类名的首字母必须大写') 5 6 if '__doc__' not in class_dir or not class_dir['__doc__'].strip(): 7 raise TypeError('必须有注释,且注释不能为空') 8 super().__init__(class_name,class_bases,class_dir) 9 10 def __call__(self, *args, **kwargs):#obj=Chinese('alex',age=18),self=Chinese,args=('alex',),kwargs={'age': 18} 11 obj=object.__new__(self)#第一件事:先造出一个空对象 12 self.__init__(obj,*args, **kwargs)#第二件事:初始化obj 13 return obj#第三件事:返回obj 14 15 class Chinese(metaclass=Mymeta):#Chinese=type(...) 16 ''' 17 中国人的类 18 ''' 19 country='China' 20 def __init__(self,name,age): 21 self.name=name 22 self.age=age 23 24 def talk(self): 25 print('%s is talking'%self.name) 26 27 obj=Chinese('alex',age=18) 28 print(obj.__dict__)#------->{'name': 'alex', 'age': 18}
因此:如果我们想控制类实例化的行为,那么需要先储备知识__call__方法的使用。
九、异常处理
1、常见异常:
AttributeError 试图访问一个对象没有的树形,比如foo.x,但是foo没有属性x IOError 输入/输出异常;基本上是无法打开文件 ImportError 无法引入模块或包;基本上是路径问题或名称错误 IndentationError 语法错误(的子类) ;代码没有正确对齐 IndexError 下标索引超出序列边界,比如当x只有三个元素,却试图访问x[5] KeyError 试图访问字典里不存在的键 KeyboardInterrupt Ctrl+C被按下 NameError 使用一个还未被赋予对象的变量 SyntaxError Python代码非法,代码不能编译(个人认为这是语法错误,写错了) TypeError 传入对象类型与要求的不符合 UnboundLocalError 试图访问一个还未被设置的局部变量,基本上是由于另有一个同名的全局变量,导致你以为正在访问它 ValueError 传入一个调用者不期望的值,即使值的类型是正确的
2、异常的处理:
- 如果异常时可以预知的,使用if来处理:
if处理异常1 AGE=10 2 age=input('>>: ').strip() 3 4 if age.isdigit():#判断是否为数字 5 age=int(age) 6 if age > AGE: 7 print('太大了')
- 如果异常不可被预知,此时再采用异常处理机制,try...except。
例子:如果setting.py中有5行文字,则不能第六次next(f),因此此时会直接跳到except 中,判断是否为该错误,如果是,则打印。
try异常处理1 try: 2 f=open('setting.py','r',encoding='utf-8') 3 print(next(f),end='') 4 print(next(f),end='') 5 print(next(f),end='') 6 print(next(f),end='') 7 print(next(f),end='') 8 print(next(f),end='') 9 print(next(f),end='') 10 f.close() 11 except StopIteration: 12 print('\n出错啦') 13 print('====>1')
3、有个万能异常:Exception,他可以捕获任意异常
4、异常处理的结构
- 常规结构:
1 try: 2 pass 3 except KeyRrror: 4 pass
- 常用结构
1 try: 2 pass#主代码 3 except KeyError as e: 4 pass#KeyError异常时,执行此处 5 except IndexError as e: 6 pass 7 else:#主代码没有异常时,执行此处 8 pass 9 finally: 10 pass#无论异常与否,最终均执行该处
- 主动触发异常
1 class People: 2 def __init__(self,name,age): 3 if not isinstance(name,str): 4 raise TypeError('名字必须传入str类型') 5 if not isinstance(age,int): 6 raise TypeError('年龄必须传入int类型') 7 8 self.name=name 9 self.age=age 10 11 p=People('egon','18')
1 Traceback (most recent call last): 2 File "C:/Users/。。。/Desktop/python/oldboypython/day5/30try_except.py", line 111, in <module> 3 p=People('egon','18') 4 File "C:/Users/。。。/Desktop/python/oldboypython/day5/30try_except.py", line 106, in __init__ 5 raise TypeError('年龄必须传入int类型') 6 TypeError: 年龄必须传入int类型
- 自定义异常
1 class MyException(BaseException): 2 def __init__(self,msq): 3 super().__init__() 4 self.msq=msq 5 6 def __str__(self): 7 return '%s'%self.msq 8 try: 9 raise MyException('wozide') 10 except MyException as e: 11 print(e)
1 wozide - 断言(用的较少,此处不细讲)
格式:assert 条件

浙公网安备 33010602011771号