ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

python之描述符应用与类的装饰器

2019-08-11 20:53:55  阅读:163  来源: 互联网

标签:__ name python self 描述符 key print 装饰 def


一、描述符应用

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')
View Code

1.2描述符的应用
描述符协议都是针对对象属性的访问。先要明白我们不会去针对一个全局的def使用property进行装饰。我们一般都是在类里面使用。可以对类的访问使用描述符(比较少用),更常用的是针对类实例的访问使用描述符协议。

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)
View Code

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)
View Code

二、类的装饰器

2.1简单的类的装饰器

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)
View Code

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)
View Code

2.3类的装饰器应用

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__)
View Code

三、元类

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()
View Code

3.2自定制元类

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)
View Code

 

标签:__,name,python,self,描述符,key,print,装饰,def
来源: https://www.cnblogs.com/changzhendong/p/11336641.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有