Python面向对象编程Day 28部分知识点
__enter__和__exit__
with obj as f:
'代码块'
1.with obj --->触发obj.__enter__(),拿到返回值
2.as f ---> f=返回值
3.with obj as f 等同于 f=obj.__enter__()
4.执行代码块
两种情况:
没有异常的情况下,整个代码块运行完毕后去触发__exit__,它的三个参数都为none
有异常的情况下,会从异常出现的位置直接触发__exit__,此时分两种情况:
如果__exit__的返回值为true,代表吞掉了异常
如果__exit__的返回值不为true,代表吐出了异常
(exit的运行完毕就代表了整个with语句的执行完毕,异常后代码块内的语句不会执行)
用途:使用with语句的目的是省去手动清理的过程,另外在需要管理一些资源比如文件,网络连接和锁的编程环境中,可以在__exit__中定制自动释放资源的机制。
异常构成简单了解
异常类,异常值,追踪信息 分别对应exc_type/exc_val/exc_tb
描述符应用
1 class typed: 2 def __init__(self,key,expected_type): 3 self.key=key 4 self.expected_type=expected_type 5 def __get__(self, instance, owner): #instance是p1实例 6 print('get方法') 7 return instance.__dict__[self.key] 8 def __set__(self, instance, value): 9 print('set方法') 10 if not isinstance(value,self.expected_type): 11 raise typeerror('%s 传入的类型不是%s' %(self.key,self.expected_type)) 12 instance.__dict__[self.key]=value 13 def __delete__(self, instance): 14 print('delete方法') 15 instance.__dict__.pop(self.key) 16 17 class people: 18 name=typed('name',str) #t1.__set__() self.__set__() 19 age=typed('age',int) #t1.__set__() self.__set__() 20 def __init__(self,name,age,salary): 21 self.name=name 22 self.age=age 23 self.salary=salary 24 25 p1=people(213,13,13.3)
输出
traceback (most recent call last):
file "g:/baidunetdiskdownload/第04阶段-python3面向对象编程(24-28)/python全栈s3 day028/day28课上代码/描述符的应用.py", line 41, in <module>
p1=people(213,13,13.3)
file "g:/baidunetdiskdownload/第04阶段-python3面向对象编程(24-28)/python全栈s3 day028/day28课上代码/描述符的应用.py", line 36, in __init__
self.name=name
file "g:/baidunetdiskdownload/第04阶段-python3面向对象编程(24-28)/python全栈s3 day028/day28课上代码/描述符的应用.py", line 25, in __set__
raise typeerror('%s 传入的类型不是%s' %(self.key,self.expected_type))
typeerror: name 传入的类型不是<class 'str'>
类的装饰器
1 def deco(obj): 2 print('==========',obj) 3 obj.x=1 4 obj.y=2 5 obj.z=3 6 return obj 7 8 @deco #foo=deco(foo) 9 class foo: 10 pass 11 12 print(foo.__dict__)
输出
========== <class '__main__.foo'>
{'__module__': '__main__', '__dict__': <attribute '__dict__' of 'foo' objects>, '__weakref__': <attribute '__weakref__' of 'foo' objects>, '__doc__': none, 'x': 1, 'y': 2, 'z': 3}
自定制property实现延迟计算功能
1 class lazyproperty: 2 def __init__(self,func): 3 # print('==========>',func) 4 self.func=func 5 def __get__(self, instance, owner): 6 print('get') 7 if instance is none: 8 return self 9 res=self.func(instance) #函数运行的时候要把实例本身传进去,而不是类 10 setattr(instance,self.func.__name__,res) 11 return res 12 # def __set__(self, instance, value): 13 # pass 14 15 class room: 16 def __init__(self,name,width,length): 17 self.name=name 18 self.width=width 19 self.length=length 20 @lazyproperty # area=lazypropery(area) 21 def area(self): 22 return self.width * self.length 23 @property # area1=property(area1) 24 def area1(self): 25 return self.width * self.length 26 27 r1=room('厕所',1,1) 28 print(r1.__dict__) 29 30 # 实例调用 31 print(r1.area) 32 print(r1.__dict__) 33 print(room.__dict__) 34 35 # 类调用 被描述符代理的属性 instance传的是none owner不变 36 print(room.area) 37 38 # 不再调用get方法,因为此时有实例属性, 39 # 其优先级高于非数据描述符 若此时加上set属性就无法实现了 40 print(r1.area) 41 print(r1.area)
输出
{'name': '厕所', 'width': 1, 'length': 1}
get
1
{'name': '厕所', 'width': 1, 'length': 1, 'area': 1}
{'__module__': '__main__', '__init__': <function room.__init__ at 0x000001efb23ea620>, 'area': <__main__.lazyproperty object at 0x000001efb07d8908>, 'area1': <property object at 0x000001efb0799688>, '__dict__': <attribute '__dict__' of 'room' objects>, '__weakref__': <attribute '__weakref__' of 'room' objects>, '__doc__': none}
get
<__main__.lazyproperty object at 0x000001efb07d8908>
1
1
property补充
1 class foo: 2 @property 3 def aaa(self): 4 print('get的时候运行我啊') 5 6 # 下面两个函数依附于静态属性存在 7 @aaa.setter 8 def aaa(self,val): 9 print('set的时候运行我啊',val) 10 @aaa.deleter 11 def aaa(self): 12 print('del的时候运行我啊') 13 #只有在属性aaa定义property后才能定义aaa.setter,aaa.deleter 14 f1=foo() 15 f1.aaa 16 f1.aaa='aaa' 17 del f1.aaa
#另一种写法,效果一样
class foo:
def get_aaa(self):
print('get的时候运行我啊')
def set_aaa(self,val):
print('set的时候运行我啊',val)
def del_aaa(self):
print('del的时候运行我啊')
aaa=property(get_aaa,set_aaa,del_aaa) #顺序不要变
f1=foo()
f1.aaa
f1.aaa='aaa'
del f1.aaa
输出
get的时候运行我啊
set的时候运行我啊 aaa
del的时候运行我啊
元类
type元类是类的类,是类的模板。元类是用来控制如何创建类的,正如类是创建对象的模板一样。元类的实例为类,正如类的实例为对象。
1 def say_hi(name): 2 return('hello,%s'%name) 3 ffo=type('ffo',(object,),{'gender':'female','say_hi':say_hi}) 4 print(ffo) 5 print(ffo.__dict__) 6 print(ffo.say_hi('chenyuan')) 7 print('your gender is %s'%ffo.gender)
输出
<class '__main__.ffo'>
{'gender': 'female', 'say_hi': <function say_hi at 0x000001cf9911c1e0>, '__module__': '__main__', '__dict__': <attribute '__dict__' of 'ffo' objects>, '__weakref__': <attribute '__weakref__' of 'ffo' objects>, '__doc__': none}
hello,chenyuan
your gender is female
实例调用函数,会自动把实例本身传进去当参数,而类调用函数时如果需要得写self
自定制元类
1 class mytype(type): 2 def __init__(self,a,b,c): 3 print('元类的构造函数执行') 4 # print(a) 5 # print(b) 6 # print(c) 7 def __call__(self, *args, **kwargs): 8 # print('=-======>') 9 # print(self) 10 # print(args,kwargs) 11 obj=object.__new__(self) #object.__new__(foo)-->f1 12 self.__init__(obj,*args,**kwargs) #foo.__init__(f1,*arg,**kwargs) 13 return obj 14 class foo(metaclass=mytype): #foo=mytype(foo,'foo',(),{})---》__init__ 15 def __init__(self,name): 16 self.name=name #f1.name=name 17 # print(foo) 18 # f1=foo('alex') 19 # print(f1) 20 21 f1=foo('alex') 22 print(f1) 23 print(f1.__dict__)
输出
元类的构造函数执行
<__main__.foo object at 0x0000025a13005048>
{'name': 'alex'}