前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >关于python类中描述器-类型检查、延迟和代理

关于python类中描述器-类型检查、延迟和代理

作者头像
python与大数据分析
发布2022-03-11 13:57:02
3430
发布2022-03-11 13:57:02
举报
文章被收录于专栏:python与大数据分析

python学习深水区,仅供自己参考

代码语言:javascript
复制
# 类型检查的描述器
class Typed:
    #变量名称,期待的数据类型
    def __init__(self, name, expected_type):
        self.name = name
        self.expected_type = expected_type
    #获取字典里的变量名称
    def __get__(self, instance, cls):
        if instance is None:
            return self
        else:
            return instance.__dict__[self.name]
    #设置变量,如果不符合期望类型抛出异常
    def __set__(self, instance, value):
        if not isinstance(value, self.expected_type):
            raise TypeError('Expected ' + str(self.expected_type))
        instance.__dict__[self.name] = value
    #删除变量
    def __delete__(self, instance):
        del instance.__dict__[self.name]

# Class decorator that applies it to selected attributes
# 类型检查的描述器
def typeassert(**kwargs):
    #{'name': <class 'str'>, 'shares': <class 'int'>, 'price': <class 'float'>}
    def decorate(cls):
        for name, expected_type in kwargs.items():
            # Attach a Typed descriptor to the class
            # 给这个类添加一个类型描述器
            setattr(cls, name, Typed(name, expected_type))
        return cls
    return decorate

# 描述器应用样例
@typeassert(name=str, shares=int, price=float)
class Stock:
    def __init__(self, name, shares, price):
        self.name = name
        self.shares = shares
        self.price = price
    def __str__(self):
        return 'name=,{},shares={},price={}'.format(self.name,self.shares,self.price)

#延迟计算属性
#将一个只读属性定义成一个property,只在访问的时候才会计算结果
#一旦被访问,结果将会缓存起来,不用每次计算
#定义延迟属性的方法是通过描述器类@lazyproperty
class lazyproperty:
    def __init__(self,func):
        self.func=func
    def __get__(self,instance,cls):
        if instance is None:
            return self
        else:
            value=self.func(instance)
            setattr(instance,self.func.__name__,value)
            return value
import math
#惰性描述器实例
class Circle:
    def __init__(self,radius):
        self.radius=radius
    @lazyproperty
    def area(self):
        print('Computing area')
        return math.pi*self.radius**2
    @lazyproperty
    def perimeter(self):
        print('Computing perimeter')
        return 2*math.pi*self.radius

# 属性的代理访问
# 一个被代理的类
class A:
    def __init__(self):
        print('class A init')
    def fun1(self,x):
        print('class A func1 ')
        return x
    def fun2(self,x):
        print('class A func2 ')
        return x
# 实现代理的类
class B1:
    #简单代理
    def __init__(self):
        self._a=A()
    def fun1(self,x):
        print('proxy class B1 func1')
        return self._a.fun1(x)
    def fun2(self,x):
        print('proxy class B1 func2')
        return self._a.fun2(x)
    def fun3(self,x):
        print('proxy class B1 func3')

# 大量的方法需要代理
class B2:
    #使用__getattr__的代理,代理方法比较多的时候
    def __init__(self):
        self._a=A()
    def fun3(self,x):
        print('proxy class B2 func3')
    def __getattr__(self, name):
        #这个方法在访问的 attribute 不存在的时候被调用
        print('B2 getattr')
        return getattr(self._a,name)

#实现代理模式
class B3:
    def __init__(self,obj):
        self._obj=obj
    def __getattr__(self, name):
        print('getattr:',name)
        return getattr(self._obj,name)
    def __setattr__(self, name, value):
        if name.startswith('_'):
            super().__setattr__(name,value)
        else:
            print('setattr:', name)
            setattr(self._obj,name,value)
    def __delattr__(self, name):
        if name.startswith('_'):
            super().__delattr__(name)
        else:
            print('delattr:', name)
            delattr(self._obj,name)

if __name__ == '__main__':
    stock1=Stock('stocktest',2,10.2)
    #--------------------
    #初始化时的顺序
    #先执行@typeassert(name=str, shares=int, price=float)
    #再执行函数typeassert,进行参数传递
    #再执行Typed.__init__,进行参数名和参数类型初始化
    #--------------------
    #执行时的顺序
    #先执行stock.__init__
    #再执行Typed.__set__
    print(stock1)
    #name=,stocktest,shares=2,price=10.2
    #stock2 = Stock('stocktest', 2.2, 10.2)
    #TypeError: Expected <class 'int'>
    #---------------------
    #延迟描述器
    #先扫描Circle类中的@lazyproperty的函数
    #再执行lazyproperty.__init__,进行初始化
    c=Circle(4)
    print(c.radius)
    print(c.area)
    # Computing area
    # 50.26548245743669
    print(c.perimeter)
    # Computing perimeter
    # 25.132741228718345
    print(c.area)
    # 50.26548245743669
    print(c.perimeter)
    # 25.132741228718345
    # -------------------------
    #几种代理机制
    b=B1()
    b.fun1(11)
    # proxy class B1 func1
    # class A func1
    b.fun2(12)
    # proxy class B1 func2
    # class A func2
    b.fun3(13)
    # proxy class B1 func3
    b = B2()
    b.fun1(21)
    # B2 getattr
    # class A func1
    b.fun2(22)
    # B2 getattr
    # class A func2
    b.fun3(23)
    # proxy class B2 func3
    a=A()   #class A init
    p=B3(a)
    print(p.fun1(21))   #getattr: fun1  class A func1 #21
    print(p.fun2(3))    #getattr: fun2  class A func2   3

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-12-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 python与大数据分析 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档