python教程:描述符应用与类的装饰器
一、描述符应用
1.1上下文管理协议
在上文中我们提到with语句中的上下文管理器。with语句可以如此简单但强大,主要依赖于上下文管理器。那么什么是上下文管理器?上下文管理器就是实现了上下文协议的类,而上下文协议就是一个类要实现__enter__()和__exit__()两个方法。一个类只要实现了__enter__()和__exit__(),我们就称之为上下文管理器下面我们具体说下这两个方法。
-
__enter__():主要执行一些环境准备工作,同时返回一资源对象。如果上下文管理器open(“test.txt”)的__enter__()函数返回一个文件对象。 -
__exit__():完整形式为__exit__(type, value, traceback),这三个参数和调用sys.exec_info()函数返回值是一样的,分别为异常类型、异常信息和堆栈。如果执行体语句没有引发异常,则这三个参数均被设为None。否则,它们将包含上下文的异常信息。__exit_()方法返回True或False,分别指示被引发的异常有没有被处理,如果返回False,引发的异常将会被传递出上下文。如果__exit__()函数内部引发了异常,则会覆盖掉执行体的中引发的异常。处理异常时,不需要重新抛出异常,只需要返回False,with语句会检测__exit__()返回False来处理异常。
如果我们要自定义一个上下文管理器,只需要定义一个类并且是实现__enter__()和__exit__()即可。
class Open:
def __init__(self,name):
self.name=name
def __enter__(self):
print('执行enter')
return self
def __exit__(self, exc_type, exc_val, exc_tb):
print('执行exit')
print(exc_type)
print(exc_val)
print(exc_tb)
return True # exit里面吞噬了异常
with Open('a.txt') as f: #触发enter
print(f)
print(adcasd) #异常触发exit
print(f.name) # 执行完后触发exit
print('1234')
with的应用:
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__
a:如果的__exit__返回值为True,代表吞噬了异常
b:如果的__exit__返回值不为True,代表吐出了异常
c: __exit__的运行完毕就代表了整个with语句的执行完毕
1.2描述符的应用
描述符协议都是针对对象属性的访问。先要明白我们不会去针对一个全局的def使用property进行装饰。我们一般都是在类里面使用。可以对类的访问使用描述符(比较少用),更常用的是针对类实例的访问使用描述符协议。
'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:778463939
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
class Typed:
def __init__(self,key,expect_type):
self.key=key
self.expect_type=expect_type
def __get__(self, instance, owner):
print('执行get方法')
return instance.__dict__[self.key]
def __set__(self, instance, value):
print('执行set方法')
if not isinstance(value,self.expect_type):
# print('传给的不是字符串,错误')
# return
raise TypeError('%s传给的不是%s' %(self.key,self.expect_type))
instance.__dict__[self.key]=value
def __delete__(self, instance):
print('执行delete方法')
instance.__dict__.pop(self.key)
class People:
name=Typed('name',str)
age=Typed('age',int) #age是数字
def __init__(self,name,age,salary):
self.name=name
self.age=age
self.salary=salary
# p1=People('czd',22,12345)
p1=People('czd',22,12345)
p1.age
print(p1.age)
1.3描述符的自定制property
class Lazyproperty:
def __init__(self,func):
self.func=func
def __get__(self, instance, owner):
print('get')
print('instance')
print('owner')
res=self.func(instance)
return res
class Room:
def __init__(self,name,width,length):
self.name=name
self.width=width
self.length=length
# @property #area=property(area)
@Lazyproperty #area=Lazyproperty(area)
def area(self):
return self.width * self.length
@property
def test(self):
return '123'
r1=Room('厕所',3,2)
print(r1.area)
# print(Room.__dict__)
print(r1.test)
print(Room.test)
二、类的装饰器
2.1简单的类的装饰器
'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:778463939
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
def deco(func):
print('-------->')
return func
# @deco #test=deco(test)
# def test():
# print('test函数运行')
# test()
@deco #Foo=deco(Foo)
class Foo:
pass
f1=Foo()
print(f1)
2.2类的装饰器加强版
def Typed(**kwargs):
def deco(obj):
for key,val in kwargs.items():
setattr(obj,key,val)
return obj
return deco
@Typed(x=1,y=1,z=3) #1.Typed(x=1,y=2,z=3) ------>deco 2.@deco------>Foo=deco(Foo)
class Foo:
pass
print(Foo.__dict__)
@Typed(name='czd')
class Bar:
pass
print(Bar.name)
2.3类的装饰器应用
'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:778463939
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
class Typed:
def __init__(self,key,expect_type):
self.key=key
self.expect_type=expect_type
def __get__(self, instance, owner):
print('执行get方法')
return instance.__dict__[self.key]
def __set__(self, instance, value):
print('执行set方法')
if not isinstance(value,self.expect_type):
# print('传给的不是字符串,错误')
# return
raise TypeError('%s传给的不是%s' %(self.key,self.expect_type))
instance.__dict__[self.key]=value
def __delete__(self, instance):
print('执行delete方法')
instance.__dict__.pop(self.key)
def deco(**kwargs):
def wrapper(obj):
for key,val in kwargs.items():
setattr(obj,key,Typed(key,val))
# setattr(People,'name',Typed('name',str)) #People.name=Typed('name',str)
return obj
return wrapper
@deco(name=str,age=int,salary=float,gender=str)
class People:
def __init__(self,name,age,salary,gender):
self.name=name
self.age=age
self.salary=salary
self.gender=gender
p1=People('czd',22,12345.8,'male')
print(People.__dict__)
三、元类
3.1元类的介绍
class Foo:
pass
print(Foo)
print(Foo.__dict__)
def __init__(self,name,age):
self.name=name
self.age=age
def test(self):
print('----->')
FFo=type('FFo',(object,),{'x':1,'__init__':__init__,'test':test})
print(FFo)
print(FFo.__dict__)
f1=FFo('czd',23)
print(f1.name)
f1.test()
3.2自定制元类
'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:778463939
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
class Mytype(type):
def __init__(self,a,b,c):
print('元类的构造函数执行')
print(a)
print(b)
print(c)
def __call__(self, *args, **kwargs):
print('------>')
print(self)
print(args,kwargs)
obj=object.__new__(self) #------>f1
self.__init__(obj,*args,**kwargs)
return obj
class Foo(metaclass=Mytype): #Mytype(4个参数)-----》__init__ --------->(self,'Foo',(),{})
def __init__(self,name): #f1.name=name
self.name=name
# f1=Foo('name')
# print(Foo)
f1=Foo('czd')
print(f1.__dict__)
print(f1)
本文来自博客园,作者:I'm_江河湖海,转载请注明原文链接:https://www.cnblogs.com/jhhh/p/16761587.html

浙公网安备 33010602011771号