Python第六章 面向对象
第六章 面向对象
1.面向对象初了解
面向对象的优点:
1.对相似功能的函数,同一个业务下的函数进行归类,分类
2.类是一个公共的模板,对象就是从具体的模板中实例化出来的,得到对象就得到一切
类:具有相同属性和功能的一类事物
对象:某个类的具体表现
2.面向对象的结构
class Human:#类名不要用下划线
#第一部分:静态属性
mind = '有思想' #类的属性 (静态属性,静态字段)
#第二部分:动态方法
def eat(self):#方法
print('人类都需要吃饭')
3.从类名的角度研究类
1.类名查看类中所有的内容
print(Human.__dict__)
#结果:
#{'__module__': '__main__', 'mind': '思想', 'eat': <function Human.eat at 0x000001AD41659D08>, '__dict__': <attribute '__dict__' of 'Human' objects>, '__weakref__': <attribute '__weakref__' of 'Human' objects>, '__doc__': None}
2.类名操作类中的静态属性 (万能的点)
1.增:
Human.body = '有躯体'
print(Human.__dict__)
2.删:del Human.mind
del Huamn.mind
3.改:Human.mind = 'live脑残'
Human.mind = 'live脑残'
4.查:print(Human.mind)
print(Human.mind)
3.类名调用类中的方法
一般类中的(除了静态方法和类方法)方法不会通过类名调用
Human.eat(1)#self,需要传参,对象不需要,默认传对象名
4.从对象的角度研究类
1.实例化对象:
obj = Human()#实例化过程
#得到一个返回值,返回值就是对象,实例
2.实例化一个对象发生三件事:
1.开辟一个对象空间。
2.自动执行object中的__new__()方法,在内存中开辟一个对象空间.
3.运行__init__方法内的代码,给对象空间封装属性
class Human:
mind = '有思想'
def __init__(self,name,age):
self.name = name
self.age = age
def eat(self):
print('人类都需要吃饭')
obj = Human()#将obj传给了self,自动执行__init__()函数
print(obj)#结果:<__main__.Human object at 0x00000210B6A48E80>
#传参:
obj = Human('qq',18)
print(obj.name,obj.age)
'''
结果:qq 18
'''
print(obj.__dict__)#对象的属性,字典的形式
'''
结果:{'name': 'qq', 'age': 18}
'''
3.对象操作对象空间的属性
1.对象查看对象空间的所有属性:
1.print(obj.__dict__):
obj = Human('qq',18)
print(obj.__dict__)
2.对象操作对象空间的属性
1.增:obj.sex = 'laddy_boy'
2.删:del obj.age
3.改:obj.age = 58
4.查:print(obj.sex)
4.对象查看类中的属性
对象不允许修改类中的属性,只允许查看。
obj = Human('qq',18)
print(obj.mind)#通过对象查看类中的属性
obj.mind = '无脑'
print(obj.mind)
print(Human.mind)
'''
类中的属性并没有更改,而是对象中新增了mind属性
'''
5.对象调用类中的方法
class Human:
mind = '有思想'
def __init__(self,name,age):
self.name = name
self.age = age
def eat(self):
print(f'{self.name}都需要吃饭')
def work(self):
print(f'{self.name}都会工作')
obj = Human('戴维',23)
obj.work()
obj.eat()
6.一个类可以实例化多个对象
obj1 = Human('戴维',20)
obj2 = Human('杰西',22)
obj3 = Human('肉丝',18)
5.类的空间问题
1.添加对象的属性
#1.在类的__init__中添加,
#2.在类的方法中添加
def eat(self,argv):
self.sex = '女'
#3.在类的外部添加
sun = Human('孙','18')
sun.weight = 120
2.添加类的属性
#1.类的内部,直接定义
#2.类的外部:
Human.body = '有头有脸'
3.对象空间与类空间的关系
当对象空间与类空间有相同的的名字,对象. 要先从对象空间查找
查询顺序:
对象.名字:对象空间 _类对象指针_ -->类空间 -- >父类空间
类名.名字:类空间 --> 父类空间
6.类与类之间的关系
1.依赖关系:
有主从之分,将一个类的类名或者对象传入另一个类的方法中
class Elephant:#主
def __init__(self,name):
self.name = name
def open(self,obj):
print(f'{self.name}打开冰箱')
obj.be_open()
class Fire:#从
def __init__(self,name):
self.name = name
def be_open(self):
print(f'{self.name}冰箱被打开了')
qiqi = Elephant('琪琪')
haier = Fire('海尔')
qiqi.open(haier)
'''
结果:
琪琪打开冰箱
海尔冰箱被打开了
'''
2.组合关系:
给一个类的对象封装一个属 性,此属性为另一个类的对象(类名)
class Game:
def __init__(self,name,ad,hp):
self.name = name
self.ad = ad
self.hp = hp
def attrck(self,p):
'''
2.
#p.hp = p.hp - self.ad - self.weap.a
d
#print(f'{self.name}使用{self.weap.name}攻击{p.name},掉了{self.ad+self.weap.ad},还剩{p.hp}')
'''
def equipment(self,weap):
self.weap = weap
class Weapon:
def __init__(self,name,ad):
self.name = name
self.ad = ad
def weappon(self,p1,p2):
#1. p2.hp = p2.hp - p1.ad - self.ad
#1. print(f'{p1.name}使用{self.name}攻击{p2.name},{p2.name}掉了{p1.ad+self.ad}血量,{p2.name}还剩{p2.hp}')
gailun = Game('盖伦',10,100)
zhaoxin = Game('赵信',20,80)
baojian = Weapon('大宝剑',20)
changqiang = Weapon('长枪',15)
#1. gailun.equipment(baojian)
# 1.gailun.weap.weappon(gailun,zhaoxin)
# 1.zhaoxin.equipment(changqiang)
# 1.zhaoxin.weap.weappon(zhaoxin,gailun)
'''
2.
gailun.equipment(baojian)
gailun.attrck(zhaoxin)
gailun.attrck(zhaoxin)
'''
7.继承
1.初识继承:
专业角度:如果B类继承A类,B类就称为子类、派生类。A类就称为父类、基类、超类。
面向对象三大特性:封装、继承、多态
最顶级父类就是object
2.继承的优点:
1.减少重复代码
2.增加类之间的耦合性
3.使代码更加清晰,流畅
3.继承:单继承,多继承
1.单继承:
查询顺序单项不可逆:子类可使用父类的属性方法,父类不可使用子类的属性方法
1.1 类名执行父类属性方法,对象执行父类属性方法
class Animal:
def __init__(self,name,sex,age):
self.name = name
self.sex = sex
self.age = age
class Human(Animal):
pass
class Dog(Animal):
pass
class Cat():
pass
#Animal:父类
#Human,Dog:子类
person = Human('C罗','男',18)
#cat1 = Cat()#默认为继承object
1.2 既执行子类的方法,又执行父类的方法
方案一:不依赖于继承,使用函数的调用
方案二:依赖于继承。super(),
执行父类的方法。称为重构
class Animal:
def __init__(self,name,sex,age):
self.name = name
self.sex = sex
self.age = age
pass
def eat(self):
print('动物都需要吃饭')
class Human(Animal):
def __init__(self,name,sex,age,hobdy):
#方案一 #Animal.__init__(self,name,sex,age)#需要传入人类对象,姓名,性别,年龄
#方案二: #super(Huamn,self).__init__(name,sex,age)#完整写法
super().__init__(name,sex,age)#简写
self.hobdy = hobdy
pass
def eat(self):
super().eat()
print(f'{self.name}需要吃饭')
human1 = Human('涛涛','雌','48','唱跳')
print(human1.__dict__)
human1.eat()
'''
结果:
{'name': '涛涛', 'sex': '雌', 'age': '48', 'hobdy': '唱跳'}
动物都需要吃饭
涛涛需要吃饭
'''
2.多继承:
python中类分为两种:
python2.x:python 2.2之前都是经典类,python2.2之后,经典类与新式类共存
python3.x:全是新式类
1.经典类:不继承object类,遵循深度优先原则:从左至右。
2.新式类:继承object类,遵循mro(C3)算法
关于mro算法:
- mro序列:
class B(A):
pass
mro(B) = mro(B(A))
= [B] + merge(mro(A) + [A])
= [B,A]
- 表头和表尾
表头:列表的第一个元素
表尾:列表中除表头以外的所有元素(可以为空)
+操作:[A] + [B] = [A,B]
- merge规则:
如计算merge( [E,O], [C,E,F,O], [C] )
有三个列表 : ① ② ③
1 merge不为空,取出第一个列表列表①的表头E,进行判断
各个列表的表尾分别是[O], [E,F,O],E在这些表尾的集合中,因而跳过当前当前列表
2 取出列表②的表头C,进行判断
C不在各个列表的集合中,因而将C拿出到merge外,并从所有表头删除
merge( [E,O], [C,E,F,O], [C]) = [C] + merge( [E,O], [E,F,O] )
3 进行下一次新的merge操作 ......
- mro算法实例:print(A.mro())
class O:
name = 'qq'
class D(O):
pass
class E(O):
name = 'wx'
# pass
class F(O):
name = 'taobao'
class B(D,E):
pass
class C(E,F):
pass
class A(B,C):
pass
obj = A()
print(obj.name)
print(A.mro())#直接得出mro算法求出的顺序
"""
mro(A(B,C)) = [A] + merge(mro(B),mro(C),[B,C])#多继承
mro(B(D,E)) = [B] + merge(mro(D),mro(E),[D,E])#单继承:mro(D(O)) = [D,O]
= [B] + merge([D,O],[E,O],[D,E])#拿出并删除D
= [B,D] + merge([O],[E,O],[E])
= [B,D,E] + merge([O],[O])
= [B,D,E,O]
mro(C(E,F)) = [C] + merge(mro(E),mro(F),[E,F])
= [C] + merge([E,O],[F,O],[E,F])
= [C,E] + merge([O],[F,O],[F])
= [C,E,F] + merge([O],[O])
= [C,E,F,O]
mro(A(B,C)) = [A] + merge([B,D,E,O],[C,E,F,O],[B,C])
= [A,B] + merge([D,E,O],[C,E,F,O],[C])
= [A,B,D] + merge([E,O],[C,E,F,O],[C])
= [A,B,D] + merge([O],[C,E,F,O],[C])
= [A,B,D,C] +merge([O],[E,F,O])
= [A,B,D,C,E,F,O]
所以:mro()算法得出的顺序为:A-->B-->D-->C-->E-->F-->O
"""
8.封装、多态和鸭子类型
1.封装:把数据代码放到一个空间,并且可以使用(函数)
2.多态:一个事物可呈现多种形态
python默认支持多态,一个变量可以指向多种数据类型
鸭子类型:python崇尚鸭子类型(编程思路),看起来像,就是鸭子。对相同的功能定义相同的名字。
鸭子的优点:
1.好记
2.虽然A,B两个类没有关系,但是统一两个类中相似方法的方法名,在某种意义上统一标准
class A:
def login(self):
print('登录')
class B:
def login(self):
print('登录')
'''
A,B互为鸭子。
'''
9.类的约束
方法一:python语言惯于使用的一种约束方式,在父类主动抛出错误
class Payment:
def pay(self):
raise Exception('你的子类未定义pay方法')#主动报错,起到约束作用
class QQ_pay(Payment):
def pay(self,money):
print(f"QQ成功支付{money}元")
class Ali_pay(Payment):
def pay(self,money):
print(f"支付宝成功支付{money}元")
class Wechat(Payment):
def fukuan(self,money):
print(f"微信成功支付{money}元")
def pay(obj,money):#归一化设计:统一接口
obj.pay(money)
pass
#使用Wechat实例化对象并调用pay函数,就会主动报错。
方法二:借鉴于java语言,定义抽象类的概念,做到真正的强制约束
from abc import ABCMeta,abstractmethod
#抽象类,接口类:强制制定规则
class Paymet(metaclass=ABCMeta):#指定元素
@abstractmethod
def pay(self,money):
pass
class QQ_pay(Paymet):
def pay(self,money):
print(f"QQ成功支付{money}元")
class Wechat(Paymet):
def fukuan(self,money):
print(f"微信成功支付{money}元")
def pay(obj,money):
obj.pay(money)
obj = Wechat()
'''
在实例化对象时就会报错
obj = Wechat()
TypeError: Can't instantiate abstract class Wechat with abstract methods pay
'''
10.super的深度剖析
严格按照对象从属于类的mro的执行顺序执行,查询下一个类
class A:
def f1(self):
print('in A')
class Foo(A):
def f1(self):
super().f1()
print('in Foo')
class Bar(A):
def f1(self):
print('in Bar') # 1
class Info(Foo,Bar):
def f1(self):
super(Foo,self).f1()
print('in Info f1') # 2
# [Info --> Foo --> Bar --> A]
obj = Info()
obj.f1()
11.类的关于
1.类的私有成员:
在类的内部可以访问,外部不可访问,也不可在类的派生类中使用。
当遇到重要的数据,功能,(只允许本类使用的)使用私有成员
类的私有成员:类的私有属性、类的私有方法、对象私有属性
class A:
name = '涛涛'
__name = '套套'
def func(self):
print(self.name)
print(self.__name)
obj = A()
obj.func()
#可以访问
obj.__name#不可访问,会报错
#如何访问私有属性:
print(A.__dict__)
#{'__module__': '__main__', 'name': '涛涛', '_A__name': '套套', 'func': <function A.func at 0x00000237FC0F9D08>, '__dict__': <attribute '__dict__' of 'A' objects>, '__weakref__': <attribute '__weakref__' of 'A' objects>, '__doc__': None}##会发现私有属性都被加上了'_类名+私有名'
#所以调用
print(A._A__name)
2.实例方法、类方法
1.实例方法:默认参数为self的方法
2.类方法:
一般就是通过类名去调用的方法,并且自动将类名地址传给cls,但是如果通过对象调用也可以,但传的地址还是类名地址
类方法作用:
1.得到类名可以实例化对象。
2.可以操作类的属性
class A:
@classmethod
def cls_func(cls):
print(f'cls'--->{cls})
#实例化对象
obj = cls()
print(obj)
print(A)
A.cls_func()
obj1 = A()
obj.cls_func()
3.静态方法:
静态方法不依赖对象与类。静态方法就是函数
作用:保证代码的规范性,合理的划分,提高代码后续维护性。
class A:
@staticmethod
def static_func():
print('静态方法')
4.属性:
将执行一个函数需要函数名()变成直接函数名,将动态方法伪装成一个属性,虽然代码级别上没有提升,但是使其看起来更合理(本质还是方法)
class Bmi:
def __init__(self,name,height,weight):
self.name = name
self.height = height
self.weight = weight
@property
def bmi(self):
self.BMI = self.weight / self.height**2
print(self.BMI)
p1 = Bmi('w',1.75,74)
p1.bmi
property是一个组合:
应用场景:1.面试考调用流程
2.工作中如果遇到一些类似属性的方法名,可以让其伪装成属性
设置属性的两种方式:后两个return是无效的,得不到。
1.利用装饰器设置属性
class Foo:
@property
def bmi(self):
print('get的时候运行我')
@bmi.setter
def bmi(self,value):
print('set的时候运行我')
print(value)#return得不到
@bmi.deleter
def bmi(self):
print('delete时运行我')
obj = Foo()
obj.bmi
obj.bmi = 666#不是改变值,而是调用@bmi.setter装饰下的函数
del obj.bmi
2.利用实例化对象的方式设置属性
class Foo:
def get_A(self):
print('get的时候运行我')
def set_A(self,value):
print('set的时候运行我')
print(value)
def delete_A(self):
print('delete的时候运行我')
A = property(get_A,set_A,delete_A)#内置三个参数,与get,set,delet一一对应
f1 = Foo()
f1.A
f1.A = '666'
del f1.A
5.内置函数:isinstance,issubclass
isinstance:判断的是对象与类的关系True/False
isinstance(a,b):判断对象a是否是b类或者b类的派生类实例化的对象
class A:
pass
class B(A):
pass
class C:
pass
obj = B()
print(isinstance(obj,B))
print(isinstance(obj,A))
print(isinstance(obj,C))
"""
结果:
True
True
False
"""
issubclass:类与类的关系 True/False
issubclass(a,b):判断a类是否是b类的子孙类
class A:
pass
class B(A):
pass
class C:
pass
print(issubclass(B,A))
print(issubclass(C,A))
"""
结果:
True
False
"""
12.元类type
type:获取对象从属于的类
python中一切皆对象,类在某种意义上也是一个对象,python中自己定义的类以及大部分内置类,都是有type元类(构建类)实例化来的
type与object的关系:
print(type(object))
#object类是type类的一个实例
print(issubclass(type,object))
#type类是object类的子孙类
13.反射
程序对自己内部代码的一种自省方式
反射是什么:通过字符串去操作对象的方式
反射是一个组合:hasattr、getattr、setattr、delattr(四个内置函数)
1.实例化对象的角度:
class Human:
country = '中国'
def __init__(self,name,age):
self.name = name
self.age = age
def func(self):
print('is func')
obj = Human('涛涛',80)
#hasattr、getattr
#hasattr返回True/False,getattr获取对象,没有会报错,可设置默认返回值
print(hasattr(obj,'name'))
f = getattr(obj,'func')
f()
#setattr,delattr用的少
#setattr:添加属性,delattr删除属性
setattr(obj,'sex','男')
print(obj.__dict__)
delattr(obj,'name')
print(obj.__dict__)
2.从类的角度:
class Human:
country = '中国'
def __init__(self,name,age):
self.name = name
self.age = age
def func(self):
print('is func')
if hasattr(A,'country'):
print(getattr(A,'country'))
3.从其他模块:
import other
#找到other.py对象的A类,实例化对象
print(getattr(other,'A'))
obj = getattr(other,'A')('涛涛')
#对实例化对象反射取值
print(getattr(obj,'name'))
4.从当前模块:
import sys
print(sys.modules[__name__])#获取当前文件对象名
def func1():
print('in 本模块这个对象')
pass
getattr(sys.modules[__name__],'func1')()
#当本文件有很多函数(名字递增),反射调用所有函数:
func_list = [f'func{i}' for i in range(1,5)]
for func in func_list:
getattr(sys.modules[__name__],func)()
14.函数与方法的区别
1.总结:函数都是显性传参,方法都有隐形传参
python 中一切皆对象, 类在某种意义上也是一个对象,python中自己定义的类,以及大部分内置类,都是由type元类(构建类)实例化得来的.
python 中一切皆对象, 函数在某种意义上也是一个对象,函数这个对象是从FunctionType这个类实例化出来的.
python 中一切皆对象, 方法在某种意义上也是一个对象,方法这个对象是从MethodType这个类实例化出来的.
1.通过打印函数名的方式区分什么是方法,什么是函数
def func1():
pass
class A:
def func2():
pass
pass
print(func1)
print(A.func2)
"""
通过类名调用的类中的方法叫做函数,结果:
<function func1 at 0x0000022B99002F28>
<function A.func2 at 0x0000022B9ACDABF8>
"""
obj = A()
print(obj.func2)
"""
通过对象调用的方法叫方法,结果:
<bound method A.func2 of <__main__.A object at 0x0000022B9ACD9198>>
"""
2.借助模块判断是方法还是函数
from types import FunctionType
from types import MethodType
def func():
pass
class A:
def func(self):
pass
obj = A()
#FunctionType:判断是否为函数
#MethodType:判断是否为方法
print(isinstance(func,FunctionType)) # True
print(isinstance(A.func,FunctionType)) # True
print(isinstance(obj.func,FunctionType)) # False
print(isinstance(obj.func,MethodType)) # True
15.特殊双下方法
双下方法:原来是开发python的程序员在源码中使用的。
双下方法:你不知道你干了什么就触发了双下方法
双下方法要慎用。
1.__len__():
必须有返回值且返回值必须为int型
#计算实例化对象的属性个数
class B:
def __init__(self,name,age):
self.name = name
self.age = age
def __len__(self):#返回对象的属性个数
return len(self.__dict__)
pass
b = B('taotao',23)
print(b.len(b))
2.__hash__():
获取哈希值,必须有返回值且返回值必须是可哈希类型
class A:
def __init__(self):
self.a = 1
self.b = 2
def __hash__(self):
return hash(str(self.a)+str(self.b))
pass
a =A()
print(hash(a))
3.__str__()、__repr__():
打印对象时触发,二者同时存在时,只执行__str__()。(str对象或repr对象也会触发)-->必须有返回值且返回值必须为字符串
class A:
def __init__(self):
pass
def __str__(self):
return '哈哈'
def __str__(self):
return '嘿嘿'
pass
a = A()
print(a)
print(str(a))
print('%s'%a)
print(repr(a))
4.__call__()😗***
当对象后面加括号或类()()触发执行从属于类(父类)的__call__方法。
class Foo:
def __init__(self):
pass
def __call__(self,*args,**kwargs):
print('__call__')
obj = Foo()
obj()
5.__eq__():
判断是否相等
class A:
def __init__(self):
self.a = 1
self.b = 2
def __eq__(self,obj):
if self.a == obj.a and self.b == obj.b:
return True
a = A()
b = A()
print(a == b)
6.__del__():
析构方法,当对象在内存中被释放时,自动触发执行。
注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。
class A:
def __del__(self):
print(666)
obj = A()
del obj
7.__new__()😗**
new一个对象,构造方法
类名()
- 先触发 object的__new__方法,此方法在内存中开辟一个对象空间.
- 执行__init__方法,给对象封装属性.
1.__new__方法:
class A:
def __init__(self):
self.x = 1
print('in init function')
def __new__(cls,*args,**kwargs):
print('in new function')
return object.__new__(A)#object类中的方法
pass
#对象时object类中的__new__方法产生了一个对象。
a = A()
#先执行__new__,在执行__init__,__init__中不能有return
2.python中的设计模式: 单例模式
一个类只允许实例化一个对象
优点:节省内存
#单例模型
class A:
__instance = None
def __init__(self,name):
self.name = name
def __new__(cls,*args,**kwargs):
if not cls.__instance:
cls.__instance = obj.__new__(cls)
return cls.__instance
pass
obj = A('alex')
print(obj)
obj1 = A('taotao')
print(obj1)
8.__item__():系列
__getitem__ ()、__setitem__()、__delitem__():对象做类似于字典的(增删改查)触发item系列
__delattr__():对象. 属性 触发此方法
class Foo:
def __init__(self,name):
self.name = name
def __getitem__(self, item):#查
print(item)
return self.__dict__[item]
def __setitem__(self, key, value):#增、改
self.__dict__[key] = value
print(self.__dict__)
def __delitem__(self, key):#删
super().__delattr__(key)
print(self.__dict__)
#删对象.属性触发
def __delattr__(self, item):
super().__delattr__(item)
print(self.__dict__)
print(item)
f1 = Foo('sb')
print(f1['name'])
f1['ac'] = 2
del f1['ac']
print(f1.__dict__)
# del f1.ac
# print(f1.name)
9.__enter__()、__exit__ () with,上下文管理
实例化对象的第二种方式:必须基于enter和exit这两个方法
class A:
def __init__(self,name):
self.name = name
def __enter__(self):#开启上下文管理器对象时触发此方法
self.name = self.name + '侬好' #第一步
print(111)
return self
#!!!必须写,将实例化的对象(self)返回
def __exit__(self, exc_type, exc_val, exc_tb):# 执行完上下文管理器对象f1时触发此方法
print(333)#第三步
self.name = self.name + '好个鸡儿'
with A('sb') as obj:
print(222)
print(obj.name)#第二步
print(obj.name)#第四步
"""结果:
111
222
sb侬好
333
sb侬好好个鸡儿"""
10.__iter__():将对象变成可迭代对象
class A:
def __init__(self,name):
self.name = name
def __iter__(self):
for i in range(10):
yield i
def __next__(self):
pass
obj = A('sb')
# print('__iter__'in dir(obj))
for i in obj:
print(i)
print(obj.name)
o = iter(obj.name)
print(next(o))
16.异常处理:
异常处理的好处:
- 用户的体验良好
- 使代码更健壮性,容错性
1.错误分类:语法错误,逻辑错误
如果你对错误信息不关心,只是想要排除错误让程序继续运行. 用万能异常
#万能异常:处理所有python识别的异常
try:
pass
except Exception as e:
print(e)
pass
#单,多分支异常结构:你对错误信息要进行明确的分流,让你的程序多元化开发.
- try else finally
except 必须依赖try,else必须依赖except和try,finally只依赖try
finally:在异常出现之前,执行finally中的语句
try:
pass
except:
pass
else:
print('如果没有异常则执行这里')
finally:
print(666)
- finally用处:用在关闭数据库连接,文件句柄关闭,数据保存等。
with open('test1.txt','r+',encoding = 'utf-8') as f:
try:
for i in f1:
print(i)
finally:
f1.close()#防止出现异常,文件不能关闭。
- 在return结束函数之前,执行finally代码,在break之前执行:
def func():
try:
print(111)
return 333
finally:
print(222)
pass
pass
print(func())
"""结果:
111
222
333"""
#在break之前执行
while 1:
try:
print(111)
break
finally:
print(222)
- 主动触发异常:
raise ValueErro('出现了value错误')
- 断言:展现一种强硬的态度
#assert 条件
name = 'sb'
n1 = input('name:')
assert name == n1
print(111)
#如果name 不等于 n1 ,会直接报错
- 自定义异常
python中提供了很多错误类型,但不是全部的错误
class SbError(BaseException):#自定义的错误必须继承于BaseException
def __init__(self,msg):
self.msg = msg
def __str__(self):
return self.msg
try:
raise SbError('你犯错了')
except SbError as e:
print(e)
"""结果:你犯错了"""