• 描述符和类的装饰器(三十九)


    简单实现

    def deco(obj):
        print("---->装饰器")
        obj.x = 1
        obj.y = 2
        obj.z = 3
        return obj
    
    @deco
    class Foo:
        pass
    
    f = Foo()
    print(Foo.__dict__)
    '''
    ---->装饰器
    {'__module__': '__main__', 
    'z': 3, 'y': 2, '__doc__': None, '__weakref__': <attribute '__weakref__' of 'Foo' objects>, 
    'x': 1, '__dict__': <attribute '__dict__' of 'Foo' objects>}
    '''

    加强版

    def Typed(**kwargs):
        def deco(obj):
            for key, value in kwargs.items():
                setattr(obj, key, value)
            return obj
        return deco
    
    @Typed(x=1, y=2, z=3)
    class Foo:
        pass
    
    @Typed(name="zhangsan")
    class People:
        pass

    应用:

    class Typed:
        def __init__(self,key, expected_type):
            self.key = key
            self.expected_type = expected_type
        def __get__(self, instance, owner):
            return instance.__dict__[self.key]
        def __set__(self, instance, value):
            if not isinstance(value, self.expected_type):
                raise TypeError("%s is not %s" %(value, self.expected_type))
            instance.__dict__[self.key] = value
        def __delete__(self, instance):
            instance.__dict__.pop(self.key)
    
    def deco(**kwargs):
        def wrapper(obj):
            for key, value in kwargs.items():
                setattr(obj, key, Typed(key, value))
            return obj
        return wrapper
    
    @deco(name=str, age=int, gender=str) # 加括号就要运行,结果wrapper = wrapper(People)
    class People:
        def __init__(self, name, age, gender):
            self.name = name
            self.age = age
            self.gender = gender
    
    p1 = People('zhangsan', 18, 'male')
    print(People.__dict__)

    描述符总结

    描述符是可以实现大部分python类特性中的底层魔法,包括@classmethod,@staticmethd,@property甚至是__slots__属性

    描述父是很多高级库和框架的重要工具之一,描述符通常是使用到装饰器或者元类的大型框架中的一个组件.

    class Lazyproperty:
        def __init__(self, func):
            self.func = func
        def __get__(self, instance, owner):
            return self.func(instance)
    
    class Room:
        def __init__(self, w, h):
            self.width=w
            self.height=h
    
        @Lazyproperty
        def cal_area(self):
            return self.width * self.height
    r = Room(4, 5)
    print(r.cal_area)
    class Lazyproperty:
        def __init__(self, func):
            self.func = func
        def __get__(self, instance, owner):
            print('get...')
            if instance is None:
                return self
            res=self.func(instance)
            setattr(instance, self.func.__name__, res)
            return res
    
    class Room:
        def __init__(self, w, h):
            self.width=w
            self.height=h
    
        @Lazyproperty
        def cal_area(self):
            return self.width * self.height
    r = Room(4, 5)
    print(r.__dict__) # {'height': 5, 'width': 4}
    print(r.cal_area) # #先从自己的属性字典找,没有再去类的中找,然后出发了area的__get__方法
    print(r.__dict__) # {'cal_area': 20, 'height': 5, 'width': 4}
    print(r.cal_area) #先从自己的属性字典找,找到了,是上次计算的结果,这样就不用每执行一次都去计算
    print(r.cal_area)
    '''
    get...
    20
    20
    20
    # 只触发了一次__get__方法,后面直接从对象的字典属性调用
    '''
    #缓存不起来了
    
    class Lazyproperty:
        def __init__(self,func):
            self.func=func
        def __get__(self, instance, owner):
            print('这是我们自己定制的静态属性,r1.area实际是要执行r1.area()')
            if instance is None:
                return self
            else:
                value=self.func(instance)
                instance.__dict__[self.func.__name__]=value
                return value
            # return self.func(instance) #此时你应该明白,到底是谁在为你做自动传递self的事情
        def __set__(self, instance, value):
            print('hahahahahah')
    
    class Room:
        def __init__(self,name,width,length):
            self.name=name
            self.width=width
            self.length=length
    
        @Lazyproperty #area=Lazyproperty(area) 相当于定义了一个类属性,即描述符
        def area(self):
            return self.width * self.length
    
    print(Room.__dict__)
    r1=Room('alex',1,1)
    print(r1.area)
    print(r1.area) 
    print(r1.area) 
    print(r1.area) #缓存功能失效,每次都去找描述符了,为何,因为描述符实现了set方法,它由非数据描述符变成了数据描述符,数据描述符比实例属性有更高的优先级,因而所有的属性操作都去找描述符了
  • 相关阅读:
    composer
    brew转为国内源
    轻松生成一个golang的docker应用程序
    轻松生成一个vue的静态nginx
    【OS_Windows】windows server设置多用户可同时远程连接
    【OS_Linux】centos中查看已有用户信息
    【OS_Linux】查看Linux系统版本的命令
    【OS_Linux】借助终端Xshell实现Centos文件的上传与下载
    【OS_Linux】终端XShell的安装与使用
    【OS_Linux】VMware 中安装CentOS7
  • 原文地址:https://www.cnblogs.com/xiangtingshen/p/10466630.html
Copyright © 2020-2023  润新知