iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > Python >python高级之描述器
  • 266
分享到

python高级之描述器

高级python 2023-01-31 01:01:03 266人浏览 安东尼

Python 官方文档:入门教程 => 点击学习

摘要

描述器用到的方法    用到3个魔术方法: __get__()、__set__()、__delete__()     方法使用格式:         obj.__get__(self, instance, owner)      

  • 描述器用到的方法

    用到3个魔术方法: __get__()、__set__()、__delete__()
    方法使用格式:
        obj.__get__(self, instance, owner)
        obj.__set__(self, instance, value)
        obj.__delete__(self, instance)

    self: 指当前类的实例本身
    instance: 指owner的实例
    owner: 指当前实例作为属性的所属类

代码一

以下代码执行过程:
    定义B类时,执行A()赋值操作,进行A类的初始化,再打印B类调用类属性x的a1属性
    紧接着执行B类的初始化,通过b实例调用类属性的x的a1属性

class A:
    def __init__(self):
        self.a1 = 'a1'
        print('A.init')

class B:
    x  = A()
    def __init__(self):
        print('B.init')

print('-' * 20)
print(B.x.a1)

print('*' * 20)
b = B()
print(b.x.a1)


  • 描述器定义

python中,一个类中实现了__get__、__set__、__delete__三个方法中的任何一个方法,
那么这个类就是描述器.
如果仅实现了__get__,就是非数据描述符 non-data descriptor
同时实现了除__get__以外的__set__或__delete__方法,就是数据描述符 data descriptor

如果一个类的类属性设置为描述器,那么它被称为此描述器的owner属主

描述器方法何时被触发:
    当属主类中对是描述器的类属性进行访问时(即类似b.x),__get__方法被触发
    当属主类中对是描述器的实例属性通过'.'号赋值时,__set__方法被触发

代码二

class A:
    def __init__(self):
        self.a1 = 'a1'
        print('A.init')

    def __get__(self,instance,owner):
        print('A.__get__ {} {} {}'.fORMat(self,instance,owner))

class B:
    x  = A()
    def __init__(self):
        print('B.init')

print('-' * 20)
print(B.x)
# print(B.x.a1)   # AttributeError B.x为None,None没有a1属性

print('*' * 20)
b = B()
# print(b.x.a1)  # AttributeError B.x为None,None没有a1属性

调用B类的类属性,被A类__get__方法拦截,并返回值None


代码三

class A:
    def __init__(self):
        self.a1 = 'a1'
        print('A.init')

    def __get__(self,instance,owner):
        print('A.__get__ {} {} {}'.format(self,instance,owner))
        return self

class B:
    x  = A()
    def __init__(self):
        print('B.init')

print('-' * 20)
print(B.x)
print(B.x.a1)   

print('*' * 20)
b = B()
print(b.x)
print(b.x.a1)  

解决上例中的返回值为None,将A类的实例返回,可成功调用A实例的a1属性

代码四

class A:
    def __init__(self):
        self.a1 = 'a1'
        print('A.init')

    def __get__(self,instance,owner):
        print('A.__get__ {} {} {}'.format(self,instance,owner))
        return self

class B:
    x  = A()
    print(x)
    def __init__(self):
        print('B.init')
#         self.x = 100    #  实例调用x属性时,直接查实例自己的__dict__
        self.x = A()      # 实例调用x属性时,不进入A类的__get__方法
        print(self.x)      

print('-' * 20)
print(B.x)    # __get__
print(B.x.a1)    # __get__

print('*' * 20)
b = B()
print(b.x)
print(b.x.a1) 

总结: 不论是实例还是类,只要是访问了是描述器的类属性,
都会被描述器的__get__方法拦截


  • 属性的访问顺序(本质)

代码五

class A:
    def __init__(self):
        self.a1 = 'a1'
        print('A.init')

    def __get__(self,instance,owner):
        print('A.__get__ {} {} {}'.format(self,instance,owner))
        return self

    def __set__(self,instance,value):
        print('A.__set__ {} {} {}'.format(self,instance,value))

class B:
    x  = A()
    print(x)
    def __init__(self):
        print('B.init')
        self.x = 100
#         self.x = A()   # 同上面100结果类似
        print(self.x)

# print('-' * 20)
# print(B.x)
# print(B.x.a1)   

# print('*' * 20)
b = B()
# print(b.x)
# print(b.x.a1)  
print(b.__dict__)
print(B.__dict__)

屏蔽A类的__set__方法,实例的__dict__为{'x': 100}
不屏蔽A类的__set__方法,实例的__dict__为{}
__set__方法本质将实例的__dict__的属性名清空,从而达到数据描述器优先于查实例字典的假象
描述器在Python中应用非常广泛

Python的方法(包括staticmethod()和claSSMethod()) 都实现为非数据描述器.
因此,实例可以通过'.'号进行生成属性.
property()函数实现为一个数据描述器.则实例不能使用'.'号进行赋值属性.

示例

class A:
    @classmethod
    def foo(cls):
        pass

    @staticmethod
    def bar():
        pass

    @property
    def z(self):
        return 5

    def __init__(self): # 非数据描述器
        self.foo = 100
        self.bar = 200
#         self.z = 300    # z属性不能使用实例覆盖
a = A()
print(a.__dict__)
print(A.__dict__)


  • 练习


    • 实现StaticMethod装饰器,完成staticmethod装饰器的功能

  • class StaticMethod:
        def __init__(self,fn):
            self._fn = fn
    
        def __get__(self,instance,owner):
            print(self,instance,owner)
            return self._fn
    
    class A:
        @StaticMethod      # stmd = StaticMehtod(stmd)
        def stmd():
            print('stmd')
    
    print(A.__dict__)
    A.stmd()    # 类调用stmd属性

    • 实现ClassMethod装饰器,完成classmethod装饰器的功能

  • from functools import partial
    
    
    class ClassMethod:
        def __init__(self,fn):
            self._fn = fn
    
        def __get__(self,instance,owner):
            print(self,instance,owner)
            return partial(self._fn,owner)      
            # 使用partial函数将类给作为默认参数
    
    class A:
        @ClassMethod       # clsmd = ClassMethod(clsmd)
        def clsmd(cls):
            print('cls',cls.__name__)
    
    print(A.__dict__)
    A.clsmd()

    • 类初始化的参数检查

  • import inspect
    
    class Typed:
    
        def __init__(self,tp):
            self._tp = tp
    
        def __get__(self,instance,owner):
            pass
    
        def __set__(self,instance,value):
            if not isinstance(value,self._tp):
                raise ValueError(value)
            setattr(instance.__class__,self._name,value)
    
    def pcheck(cls):
        def wrapper(*args):
            sig = inspect.signature(cls)
            params = sig.parameters
            for i,(name,param) in enumerate(params.items()):
                if param.empty != param.annotation:
    #                 if not isinstance(args[i],param.annotation):
    #                     raise ValueError(args[i])
                    setattr(cls,name,Typed(param.annotation))
            return cls(*args)
        return wrapper
    
    @pcheck
    class A:
    #     a = Typed(str)
    #     b = Typed(int)
        def __init__(self,a:str,b:int):
            self.a = a
            self.b = b
    
    A('1',2)

    描述器结合装饰实现

    import inspect
    
    
    class Typed:
        def __init__(self,name,tp):
            self._name = name
            self._tp = tp
    
        def __get__(self,instance,owner):
            print('get',self,instance,owner)
            return instance.__dict__[self._name]
    
        def __set__(self,instance,value):
            print('set',self,instance,value)
            if not isinstance(value,self._tp):
                raise ValueError(value)
            instance.__dict__[self._name] = value
    
    class A:
        a = Typed('a',str)
        b = Typed('b',int)
        def __init__(self,a:str,b:int):
            self.a = a
            self.b = b
    
    a = A('1',2)
    print(a.__dict__)
    # print(type(a.a),type(a.b))
    print(a.a)

    描述器实现

    import inspect
    
    def pcheck(cls):
        def wrapper(*args):
            sig = inspect.signature(cls)
            params = sig.parameters
            for i,(_,param) in enumerate(params.items()):
                if param.empty != param.annotation:
                    if not isinstance(args[i],param.annotation):
                        raise ValueError(args[i])
            return cls(*args)
        return wrapper
    
    @pcheck    # A = pcheck(A)
    class A:
        def __init__(self,a:str,b:int):
            self.a = a
            self.b = b
    
    A('1','2')

    装饰器版本

    class A:
        def __init__(self,a:str,b:int):
            if not (isinstance(a,str) and isinstance(b,int)):
                raise ValueError(a,b)
            else:
                self.a = a
                self.b = b
    A('1',2)

    直接参数检查

    思路:
        实现参数检查的本质是判断传入的参数是否符合形参定义的类型,也就是用isinstance进行判断.
        因此参数检查的不同实现的区别在于在哪些地方拦截传入的参数,来进行检查.
        上述实现的拦截地方:
            在类初始化时,在对实例属性赋值之前拦截
            使用装饰器,和inspect模块,在实例化之前进行参数检查
            使用描述器,在初始化时对实例属性设置时,触发描述器的__set__方法,在__set__方法中进行参数检查,再对其实例的类添加类属性
                (如果添加在实例上,则会递归调用回到__set__方法)
            使用装饰器获取参数注解,给类添加有描述器的类属性,再通过描述器的方式进行参数检查


--结束END--

本文标题: python高级之描述器

本文链接: https://www.lsjlt.com/news/184090.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • python高级之描述器
    描述器用到的方法    用到3个魔术方法: __get__()、__set__()、__delete__()     方法使用格式:         obj.__get__(self, instance, owner)      ...
    99+
    2023-01-31
    高级 python
  • Python基础详解之描述符
    目录一、描述符定义二、描述符的种类和优先级三、描述符的应用四、描述符 + 类装饰器  (给 Person类添加类属性)五、利用描述符自定义 @property六、prope...
    99+
    2024-04-02
  • Python的描述符
    1、描述符的定义   描述符是与特定属性互相绑定的一种协议,通过方法被触发修改属性,这些方法包括__get__(),__set__(),__delete__().将这些方法定义在类中,即可实现描述符 2、属性与__dict__   Pyt...
    99+
    2023-01-30
    Python
  • python描述器的用法
    这篇文章主要介绍python描述器的用法,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!python有哪些常用库python常用的库:1.requesuts;2.scrapy;3.pillow;4.twisted;5....
    99+
    2023-06-14
  • python中什么是描述器
    这期内容当中小编将会给大家带来有关python中什么是描述器,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。Python的优点有哪些1、简单易用,与C/C++、Java、C# 等传统语言相比,Python对...
    99+
    2023-06-14
  • 用 Python 描述 Cookie 和
    这篇文章我们来聊聊Cookie和Session,网上有很多关于这两个知识点的描述,可惜的是大部分都没有示例代码,因此本文的重点在于示例代码。 环境 Python3.6.0 Bottle0.12.15 安装bottle pipinstall...
    99+
    2023-01-31
    Python Cookie
  • 详解Python魔法方法之描述符类
    描述符类要求: 描述符就是将某种特殊类型的类的实例指派给另一个类的属性 至少要实现以下的一个方法: •__get__(self, instance, owner) ...
    99+
    2024-04-02
  • SICP Python描述 1.1 引
    来源:1.1 Introduction 译者:飞龙 协议:CC BY-NC-SA 4.0 计算机科学是一个极其宽泛的学科。全球的分布式系统、人工智能、机器人、图形、安全、科学计算,计算机体系结构和许多新兴的二级领域,每年都会由于...
    99+
    2023-01-31
    SICP Python
  • Python中的描述器怎么使用
    这篇文章主要介绍“Python中的描述器怎么使用”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Python中的描述器怎么使用”文章能帮助大家解决问题。概述Python描述器是一个Python对象,它...
    99+
    2023-07-05
  • python中描述器有哪些分类
    这篇文章将为大家详细讲解有关python中描述器有哪些分类,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。Python的优点有哪些1、简单易用,与C/C++、Java、C# 等传统语言相比,P...
    99+
    2023-06-14
  • Python中反射和描述器总结
    反射在Python中,能够通过一个对象,找出type、class、attribute或者method的能力,成为反射。 函数与方法 内建函数:getattr(object,name[,degault])  通过name返回object的属性...
    99+
    2023-01-31
    反射 Python
  • Python描述符的使用
      前言 作为一位python的使用者,你可能使用python有一段时间了,但是对于python中的描述符却未必使用过,接下来是对描述符使用的介绍 场景介绍 为了引入描述符的使用,我们先设计一个非常简单的类: class Produ...
    99+
    2023-01-30
    Python
  • Python描述符怎么用
    这篇文章主要介绍“Python描述符怎么用”,在日常操作中,相信很多人在Python描述符怎么用问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Python描述符怎么用”的疑惑有所帮助!接下来,请跟着小编一起来...
    99+
    2023-06-17
  • Python中描述符有哪些
    这期内容当中小编将会给大家带来有关Python中描述符有哪些,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。python可以做什么Python是一种编程语言,内置了许多有效的工具,Python几乎无所不能,...
    99+
    2023-06-14
  • Python中有哪些描述符
    这篇文章将为大家详细讲解有关Python中有哪些描述符,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。python可以做什么Python是一种编程语言,内置了许多有效的工具,Python几乎无...
    99+
    2023-06-14
  • python虚拟机之描述器实现原理与源码分析
    目录从字节码角度看描述器描述器源码分析总结从字节码角度看描述器 在前面的内容当中我们已经详细分析了描述器的使用和其相关的应用,我们通常使用描述器都是将其作为类的一个类属性使用,而使用...
    99+
    2023-05-19
    python虚拟机描述器实现原理 python虚拟机描述器实现源码 python虚拟机 python描述器实现
  • Object.defineProperty()函数之属性描述对象
    目录概述Object.getOwnPropertyDescriptor()Object.getOwnPropertyNames()Object.defineProperty(),Ob...
    99+
    2024-04-02
  • 怎么在Python描述器中调用__getattribute__
    今天就跟大家聊聊有关怎么在Python描述器中调用__getattribute__,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。python有哪些常用库python常用的库:1.re...
    99+
    2023-06-14
  • Python魔法方法之描述符类的示例分析
    这篇文章给大家分享的是有关Python魔法方法之描述符类的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。描述符类要求:描述符就是将某种特殊类型的类的实例指派给另一个类的属性至少要实现以下的一个方法:•__...
    99+
    2023-06-15
  • python描述符的简单介绍
    这篇文章主要介绍“python描述符的简单介绍”,在日常操作中,相信很多人在python描述符的简单介绍问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”python描述符的简单介绍”的疑惑有所帮助!接下来,请跟...
    99+
    2023-06-01
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作