python之属性描述符与属性查找规则

描述符
import numbers
class IntgerField:
    def __get__(self, isinstance, owner):
        print(‘获取age‘)
        return self.num

    def __set__(self, instance, value):
        print(‘设置age值时‘)
        if  not isinstance(value, numbers.Integral):
            raise ValueError(‘int need‘)
        self.num = value
    def __delete__(self, instance):
        pass

class User:
    age = IntgerField()   // 数据属性描述符,查找优先级最高

user = User()
user.age = 33
print(user.age)

上述的User可以看做数据库中的表,假设我们要控制user中age的赋值类型,固然可以使用以下形式进行拦截:

class User:
    age = 33
    def __setattr__(self, name, value):
        pass               // 这里进行类型检测
又或者:
class User:
    @property
    def age(self):
        return self._num
    @age.setter
    def age(self,value):
        self._num = value // 这里进行类型检测

但是这种一两次还行,多了就是在写重复代码,所以就可用上述类IntgerField中定义__get__,__set__等实现属性描述符的方式进行拦截。

getattributegetattrsetattr、__delattr__等方法用来实现属性查找、设置、删除的一般逻辑,而对属性的控制行为就由属性对象来控制。这里单独抽离出来一个属性对象,在属性对象中定义这个属性的查找、设置、删除行为。这个属性对象就是描述符。

描述符对象一般是作为其他类对象的属性而存在。在其内部定义了三个方法用来实现属性对象的查找、设置、删除行为。这三个方法分别是:

get(self, instance, owner):定义当试图取出描述符的值时的行为。

set(self, instance, value):定义当描述符的值改变时的行为。

delete(self, instance):定义当描述符的值被删除时的行为。

其中:instance为把描述符对象作为属性的对象实例;

owner为instance的类对象。

描述符有数据描述符和非数据描述符之分

只要至少实现__get__、set、__delete__方法中的一个就可以认为是描述符;

只实现__get__方法的对象是非数据描述符,意味着在初始化之后它们只能被读取;

同时实现__get__和__set__的对象是数据描述符,意味着这种属性是可读写的。

属性查找规则

当查找对象上的某个属性时,假设是user.age,顺序先是判断该实例所指向的类以及基类的__dict__中查找,并且如果该属性数据属性描述符,就会调用描述符中的__get__方法

如果该age直接出现在obj.__dict__上,直接返回obj.__dict__[‘age‘]

如果该属性出现在User中或基类中,且该属性是非数据属性描述符,就会调用其__get__方法,如果不是非数据属性描述符,就会调用User或基类的User或基类.__dict__[‘age‘]

如果这些都没有,且User上也没有__getattr__方法,就会报错

原文地址:https://www.cnblogs.com/raind/p/10146160.html

时间: 2024-07-30 21:41:56

python之属性描述符与属性查找规则的相关文章

python 属性描述符及属性查找顺序

1 import numbers 2 class IntField: # 当一个类实现了 __get__, __set__, __delete__ 3 """ 4 数据描述符 5 """ 6 def __get__(self, instance, owner): 7 return self.value 8 def __set__(self, instance, value): 9 if not isinstance(value, numbers.

python高级编程之最佳实践,描述符与属性01

# -*- coding: utf-8 -*- # python:2.x __author__ = 'Administrator' #最佳实践 """ 为了避免前面所有的问题,必须考虑到几下几点: ~1:应该避免多重继承,可以一些设计模式来代替它 ~2:super使用必须一致,在类层次结构中,应该在所有地方都使用super或者彻底不使用它,滥用super和传统调用是一种滥用方法,建议使用super ~3:不要滥用经典类和新式类,两者都具备代码库将导致不同的mro表现 ~4:调

Java重要技术(13)内省之属性描述符PropertyDescriptor

1.1. 属性描述符(PropertyDescriptor) 可以使用PropertyDescrptor类来访问Java Bean的属性和方法. Object obj; Class beanClass = SampleBean.class; Object value; PropertyDescriptor propertyDescriptor; try { //创建对象 obj = SampleBean.class.newInstance(); //访问age属性. propertyDescri

深入理解javascript对象系列第三篇——神秘的属性描述符

× 目录 [1]类型 [2]方法 [3]详述[4]状态 前面的话 对于操作系统中的文件,我们可以驾轻就熟将其设置为只读.隐藏.系统文件或普通文件.于对象来说,属性描述符提供类似的功能,用来描述对象的值.是否可配置.是否可修改以及是否可枚举.本文就来介绍对象中神秘的属性描述符 描述符类型 对象属性描述符的类型分为两种: 数据属性和访问器属性 数据属性 数据属性(data property)包含一个数据值的位置,在这个位置可以读取和写入值.数据属性有4个特性 [1]Configurable(可配置性

JS属性描述符

var myObject = { a:2 }; Object.getOwnpropertyDescriptor(myObject,"a"); { value:2, writable:true, emumerable:true, configurable:true } 这段代码中的属性描述符不仅只有2,还有writable(可写).enumerable(可枚举).configurable(可配置)三种 在创建普通属性时属性描述符会使用默认值,我们也可以使用 Object.definePr

理解JavaScript中的属性描述符

我们把描述JavaScript中定义内部特性的属性叫做属性描述符 分为两大类:数据描述符和存取描述符 数据描述符是一个拥有可写或不可写的属性(Writable); 存取描述符不包含数据值,是一组拥有getter和setter属性的描述符: 描述符必须是这两者之一,不可能都是这两者: 数据描述符合存取描述符都具有以下的可选键值: configurable这个指的是描述,当属性的configurable的值为true的时候,该属性的描述符才可以改变,同时该属性可以从对象上被删除,默认值是false

寻找实体上SaleOrgId对应的属性描述符失败,实体不存在此属性!

表达式计算出错: FSaleOrgId.FNumber == '105' ( 寻找实体上SaleOrgId对应的属性描述符失败,实体不存在此属性![EntityType:SaleOrderFinance Propeyties:Id LocalCurrId_Id LocalCurrId ExchangeTypeId_Id ExchangeTypeId ExchangeRate PayAdvanceRate PayAdvanceAmount DiscountListId_Id DiscountLis

JS面向对象篇一、理解对象及属性特性(属性描述符)

本文内容 1.理解对象; 2.ECMAScript有两种属性类型:数据属性和访问器属性(getter和setter函数); 3.数据属性的属性特性:[[Configurable]].[[Enumerable]].[[Writable]].[[value]]; 4.访问器属性的属性特性:[[Configurable]].[[Enumerable]].[[get]].[[set]]; 5.Object.defineProperty().Object.defineProperties().Object

python高级编程之描述符与属性03

# -*- coding: utf-8 -*- # python:2.x __author__ = 'Administrator' #属性Property #提供了一个内建描述符类型,它知道如何将一个特性链接到一组方法上,采用fget参数和3个可选的参数-fset,fdel,doc最后一个参数可以提供用来定义一个后链接到特性的docstring,就像个方法,如下 class MyClass(object): def __init__(self): self._my_seceret_ting=1