• 第8.27节 Python中__getattribute__与property的fget、@property装饰器getter关系深入解析


    一、 引言
    《第7.23节 Python使用property函数定义属性简化属性访问的代码实现》《第7.26节 Python中的@property装饰器定义属性访问方法getter、setter、deleter 详解》中介绍了两种设置属性访问方法,通过设置可以在相关属性访问时调用对应的方法执行访问,支持属性简单访问(如对象名.属性名、赋值语句)、或者为了控制访问逻辑使用的。那么property函数其中的fget、@property装饰器的getter之间的关系是怎样的呢?下面我们通过案例来进行分析。

    二、 案例

    1. 案例说明:
      本案例定义类Car,其中有二个实例变量power、totaldistance、三个实例方法(构造方法、__ getattribute__方法、gettotaldistance方法)、一个装饰器和一个property函数定义属性变量语句。
      在__ getattribute__方法中将所有访问实例属性的属性名输出,并调用父类object类的__ getattribute__方法返回真正的数据。
      装饰器将实例变量power定义为carpower属性输出,虽然二者的值是一样的,但是两个不同的实例属性;
      property函数定义了totaldist属性,该属性输出的是实例变量totaldistance的值,二者值相同但实际上也是不同实例变量。然后我们执行totaldist和carpower的读取,看看输出是怎样的?
    2. 案例代码
    >>> class Car(): 
        def __init__(self, power):
            self.power = power
            self.totaldistance = 10
            
        def __getattribute__(self, properyname):
            print("In __getattribute__,you are getting  properyty: {}".format(properyname))
            return object.__getattribute__(self, properyname)  
        
        @property  
        def carpower(self): #定义carpower属性的getter只读装饰器函数
           print("execute carpower")
           return self.power
        
        def gettotaldistance(self):
            print("execute gettotaldistance")
            return self.totaldistance #定义property的fget函数
        totaldist = property(gettotaldistance,None,None,'车辆行驶总里程')  #定义totaldist属性
    
    	      
    >>> car = Car('汽油发动机')
    >>> car.carpower  #获取装饰器@property 定义属性carpower
    In __getattribute__,you are getting  properyty: carpower
    execute carpower
    In __getattribute__,you are getting  properyty: power
    '汽油发动机'
    >>> car.totaldist #获取内置函数property 定义属性totaldist 
    In __getattribute__,you are getting  properyty: totaldist
    execute gettotaldistance
    In __getattribute__,you are getting  properyty: totaldistance
    10
    >>>
    
    1. 案例截屏
      在这里插入图片描述
    2. 案例说明
      通过以上案例可以看出,使用装饰器@property 或property函数定义的属性(下称”定义属性”)访问过程是这样的:
      1> 执行__ getattribute__方法去访问“定义属性”;
      2> 调用@property的getter 或property类型的fget去执行具体的访问方法;
      3> 访问方法访问具体实例变量数据,再次触发__ getattribute__方法返回真正的数据。

    三、 总结
    通过上述案例及分析, property的fget、@property装饰器getter两者是基本是相同的,只是两种不同的实现,为了描述方便,后面统称为“property的get方法”。
    __getattribute__与“property的get方法”之间的异同点如下:

    1. 都能在对实例对象进行属性get时触发,但“property的get方法”只能针对一个“定义属性”,而__getattribute__能针对所有属性包括特殊变量进行触发,触发后参数中有具体属性名;
    2. “property的get方法”只能针对“定义属性”的实例变量,而__getattribute__还能针对实例方法;
    3. 两者在解释器使用dir、type、help访问属性时触发,只不过“property的get方法”只能针对“定义属性”触发,而__getattribute__针对实例方法和所有实例变量;
    4. “property的get方法”返回数据一般是对应方法直接访问实例(self.属性)变量,而__getattribute__不能直接访问实例(self.属性)变量,否则会触发递归调用,只能用父类的__getattribute__方法返回数据;
    5. “定义属性”由于是针对实例变量进行了查询或查询后经过运算返回的,因此它的访问首先会执行__getattribute__方法去访问“定义属性”的数据,然后该访问被定向到绑定的get方法,该get方法会再次触发__getattribute__方法去访问实际需要访问的实例变量,因此使用“property的get方法”去查询“定义属性”的数据时,肯定会触发至少两次__getattribute__方法的执行(次数需要看“property的get方法”去查询的实例变量有多少个);
    6. __getattribute__方法是截获所有通过“实例名.属性名”访问实例变量、类变量、实例方法的所有操作来控制对属性的访问,而“property的get方法”则是为了方便访问数据,提高代码的易读性而实施的属性和方法的绑定。

    本节结合案例深入分析了__getattribute__方法与“property的get方法”的异同点,。
    老猿Python,跟老猿学Python!
    博客地址:https://blog.csdn.net/LaoYuanPython

    请大家多多支持,点赞、评论和加关注!谢谢!

  • 相关阅读:
    Generate SQL from Excel
    ASP.NET Web API系列教程目录
    进阶篇:以IL为剑,直指async/await
    30分钟?不需要,轻松读懂IL
    进程简介
    二维码详解
    通过IL分析C#中的委托、事件、Func、Action、Predicate之间的区别与联系
    我是一个线程
    ServiceLocator 简单示例(转)
    特性(C#)
  • 原文地址:https://www.cnblogs.com/LaoYuanPython/p/13643715.html
Copyright © 2020-2023  润新知