Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >关于python类中描述器-类型检查、延迟和代理

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

作者头像
python与大数据分析
发布于 2022-03-11 05:57:02
发布于 2022-03-11 05:57:02
44300
代码可运行
举报
运行总次数:0
代码可运行

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# 类型检查的描述器
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 删除。

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

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Python描述符(__get__和__set__和__delete__)
描述符是什么:描述符本质就是一个新式类,在这个新式类中,至少实现了__get__(),__set__(),__delete__()中的一个,这也被称为描述符协议
Python学习者
2023/03/03
7100
python学习笔记6.5-类中描述符的使用
本文介绍了Python中类方法、静态方法、类变量、描述符以及装饰器在Python中的应用。类方法使用`@classmethod`装饰器定义,可以在不创建类实例的情况下被调用;静态方法使用`@staticmethod`装饰器定义,不会获取类的实例;类变量使用`@classproperty`装饰器定义,可以在类实例之间共享数据;描述符使用`@descriptor`装饰器定义,可以用于实现自定义的属性;装饰器是用于修改或生成其他类的函数或属性,可以增强现有类的功能或改变其行为。
锦小年
2018/01/02
7720
py3_cookbook_notes_02
最近在看Python Cookbook第三版,将看书过程中一些平时不太容易注意的知识点记录下来。 函数 可接受任意数量参数的函数 def avg(first, *rest): return (first + sum(rest)) / (1 + len(rest)) # Sample use avg(1, 2) # 1.5 avg(1, 2, 3, 4) # 2.5 import html def make_element(name, value, **attrs): keyvals =
jeremyxu
2018/05/11
1.3K0
Python面向对象编程Day 28部分
  没有异常的情况下,整个代码块运行完毕后去触发__exit__,它的三个参数都为None
py3study
2020/01/19
3830
说说Python中的property
最近在项目中,发现项目越来越大之后,之前的编写方式会留下很多坑,因此最近专门研究了一下静态语言中的方法,比如java中的bean这玩意,发现这种方式引入后,可以很有效的解决这类问题。
点点寒彬
2020/03/18
5950
Python描述器
以上代码实现了温度的摄氏温度和华氏温度之间的自动转换。其中Temperature类含有实例变量fahrenheit和类变量celsius,celsius由描述器Celsius进行代理。由这段代码引出的三点疑问:
职场亮哥
2020/10/10
5380
Pyhton Cookbook 学习笔记 ch9_02 元编程[通俗易懂]
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/136690.html原文链接:https://javaforall.cn
全栈程序员站长
2022/09/05
4680
Python-面向对像及其他
其他相关 1、isinstance(obj,cls)       检查是否obj是类cls的对象 # 针对变量 n = 123 s = "123" print isinstance(n,int) # True print isinstance(s,int) # False print isinstance(s,str) # False # 针对类 class Foo: pass obj = Foo() print isinstance(obj,Foo) # True 2、issubclass(sub,s
洗尽了浮华
2018/01/22
7140
Python - 描述器
我们可以使用 Python 自带的 property 装饰器 来控制属性的访问,下面这个例子通过 property 控制了 Person 的 age 属性的访问和修改
小歪
2019/05/14
9710
第27天面向对象之反射,绑定方法,特定的
  类中的方法为什么要这么麻烦分这么多的类型呢?当然是有运用场景了,在写类中方法的时候具体的应用设置成绑定方法还是非绑定方法主要取决于我们方法代码中是否要用到对象或者是类。下面举一个小小的案例说明一下
py3study
2020/01/20
5940
python类的装饰器
我们知道,在不改变原有代码的基础上,我们可以使用装饰器为函数添加新的功能。同理,一切皆对象,我们也可以使用装饰器为类添加类属性。
狼啸风云
2019/09/18
7850
类属性的延迟计算
目录[-] 所谓类属性的延迟计算就是将类的属性定义成一个property,只在访问的时候才会计算,而且一旦被访问后,结果将会被缓存起来,不用每次都计算。 优点 构造一个延迟计算属性的主要目的是为了提升性能 实现 class LazyProperty(object): def __init__(self, func): self.func = func def __get__(self, instance, owner): if instance i
jhao104
2018/03/20
8870
python学习笔记6.7-简化数据结构的初始化过程
我们每编写一个类的时候都需要编写一个初始化函数,那么如果编写的类当做数据结构来用,它们的初始化结构就是一样的,例如: class Stock: def __init__(self,name,s
锦小年
2018/01/02
7280
Python学习(八)---- 面向对象类之进阶
原文地址: https://blog.csdn.net/fgf00/article/details/52479307 编辑:智能算法,欢迎关注! 上期我们一起学习了python中的类
智能算法
2018/10/08
4890
Python学习(八)---- 面向对象类之进阶
python3--面向对象的进阶
反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问,检测和修改它本身状态或行为的一种能力(自省),它首先被程序语言的设计领域所采用,并在Lisp和面向对象取得了成绩
py3study
2018/08/02
3300
python 类装饰器与元类
def check_attributes(**kwargs): def decorate(cls): for key, value in kwargs.items(): if isinstance(value, Descriptor): value.name = key setattr(cls, key, value) else: setattr(cls, key, value(key)) return cls
用户5760343
2019/12/13
9440
python高级之描述器
描述器用到的方法     用到3个魔术方法: __get__()、__set__()、__delete__()     方法使用格式:         obj.__get__(self, instance, owner)         obj.__set__(self, instance, value)         obj.__delete__(self, instance)     self: 指当前类的实例本身     instance: 指owner的实例     owner: 指当前实例作为
py3study
2020/01/14
4450
python类之特殊属性和魔术方法
1 实现 StaticMethod 装饰器,实现staticmethod的部分功能
py3study
2020/01/06
1.9K0
Python基础---类的内置方法
__init__(): __init__方法在类的一个对象被建立时,马上运行。这个方法可以用来对你的对象做一些你希望的初始化。注意,这个名称的开始和结尾都是双下划线。 代码例子:
我被狗咬了
2019/09/23
5780
Python中5对必知的魔法方法
在Python中,我们可以使用下划线、字母和数字来命名函数。单词之间的下划线并没有太大的意义——它们只是通过在单词之间创建空格来提高可读性。这就是众所周知的s蛇形命名风格。例如,calculate_mean_score比calculatemeanscore更容易阅读。你可能知道,除了这种使用下划线的常见方式,我们还在函数名之前加上一个或两个下划线(例如:_func,__func) 来表示类或模块内的私有化函数,那些没有以下划线为前缀的名称被认为是公共 API。
老齐
2020/09/24
6160
相关推荐
Python描述符(__get__和__set__和__delete__)
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验