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'}