python管理属性方法总结比较

发布时间:2024年01月08日

1 python管理属性方法总结比较

python通过管理实现,实现实例在属性访问时自动运行对应代码。

获取属性值以及存储属性值对其验证和修改的时候,代码可以动态的计算属性值。

(1)__getattr__和__setattr__方法,把未定义的属性获取和所有的属性赋值指向通用的处理器方法。

(2)__getattribute__方法,把所有属性获取都指向python2.x的新式类和python3.x的所有类的一个泛型处理器方法。

(3)property内置函数,把特定属性访问定位到get和set处理器函数,也叫做特性(Property)。

(4)描述符协议,把特定属性访问定位到具有任意get和set处理器方法的类的实例。

NO管理属性方法描述
1特性1、 用property()内置函数;定义getX、setX、delX方法; 2、 用@property装饰器;定义setter、deleter方法; 3、 客户类实例属性用双下划线开头,和特性类属性区分; 4、 属性操作未定义对应方法,则报错;
2描述符1、 有__get__()、__set__()、__delete__()方法的类,为描述符; 2、 描述符实例作为客户类属性; 3、 若用描述符属性,客户类实例属性不能用双下划线开头; 4、 禁止赋值需显式声明描述符的__set__()方法为只读;
3__getattr__1、 实例访问未定义属性name,被拦截指向已定义属性 _name; 2、 对未定义属性进行判断匹配,实现对应逻辑;
4__getattribute__1、 实例访问全部属性被拦截; 2、 对属性名进行判断匹配,实现对应逻辑; 3、 通过object.__getattribute__(self,attr)避免循环;
5__setattr__1、 拦截实例属性赋值操作; 2、 通过self.__dict__[attr]=value、object.__setattr__(self,attr,value)

示例

>>> class PrintBusiCard:
    def __str__(self,obj):
        t=(obj.cardid,obj.name,obj.age,obj.addr,obj.remain2retire)
        m=map(str,t)
        return ','.join(tuple(m))
        
>>> class BusiCardProp:
    '''
        特性未定义__set__()时attr=value赋值报错
        客户类实例属性用双下划线开头
        特性的set、get直接操作__x
    '''
    cardidlen=10
    retireage=65
    def __init__(self,cardid,name,age,addr):
        self.__cardid=cardid
        self.__name=name
        self.__age=age
        self.addr=addr
    def getName(self):
        return self.__name
    def setName(self,value):
        self.__name=value
    name=property(getName,setName)
    def getAge(self):
        return self.__age
    def setAge(self,value):
        if value<=0 or value>160:
            errmsg='年龄需大于0,小于等于160'
            raise ValueError(errmsg)
        else:
            self.__age=value
    age=property(getAge,setAge)
    @property
    def cardid(self):
        return self.__cardid[:-5]+'*****'
    @cardid.setter
    def cardid(self,value):
        if len(value)!=self.cardidlen:
            errmsg='卡号长度需等于10'
            raise ValueError(errmsg)
        else:
            self.__cardid=value
    @property
    def remain2retire(self):
        return self.retireage-self.__age
    # 特性未定义__set__()时attr=value赋值报错 
    def __str__(self):
        return PrintBusiCard().__str__(self)


>>> class BusiCardDesc:
    '''
        描述符实例作为属性,访问时自动调用描述符实例的方法
        若用描述符属性,客户类实例属性不能用双下划线开头,
        因为外部类无法访问__x属性。
        若未定义__set__,attr=value赋值,直接使用默认赋值成功,
        所以只读的需显式申明
    '''
    cardidlen=10
    retireage=65
    def __init__(self,cardid,name,age,addr):
        self._cardid=cardid
        self._name=name
        self._age=age
        self.addr=addr
    
    class CardId:
        def __get__(self,instance,owner):
            return instance._cardid[:-5]+'*****'
        def __set__(self,instance,value):
            if len(str(value))!=instance.cardidlen:
                errmsg='卡号长度需等于10'
                raise ValueError(errmsg)
            else:
                instance._cardid=value
    
    class Name:
        def __get__(self,instance,owner):
            return instance._name
        def __set__(self,instance,value):
            instance._name=value
    
    class Age:
        def __get__(sel,instance,owner):
            return instance._age
        def __set__(self,instance,value):
            if value<=0 or value>160:
                errmsg='年龄需大于0,小于等于160'
                raise ValueError(errmsg)
            else:
                instance._age=value
    
    class Remain2Retire:
        def __get__(self,instance,owner):
            return instance.retireage-instance._age
        # 描述符必须显式定义__set__()为只读
        # 若未定义,attr=value赋值,直接使用默认赋值成功
        def __set__(self,instance,value):
            raise AttributeError('禁止修改')
    
    cardid=CardId()
    name=Name()
    age=Age()
    remain2retire=Remain2Retire()
    def __str__(self):
        return PrintBusiCard().__str__(self)

>>> class BusiCardGetAtrr:
    '''
        实例访问未定义属性name,被拦截指向已定义属性 _name
    '''
    cardidlen=10
    retireage=65
    def __init__(self,cardid,name,age,addr):
        self._cardid=cardid
        self._name=name
        self._age=age
        self.addr=addr
    def __getattr__(self,name):
        if name == 'cardid':
            return self._cardid[:-5]+'*****'
        elif name == 'name':
            return self._name
        elif name == 'age':
            return self._age
        elif name == 'remain2retire':
            return self.retireage-self._age
        else:
            raise AttributeError(name)
    def __setattr__(self,name,value):
        if name == 'cardid':
            if len(str(value))!=self.cardidlen:
                errmsg='卡号长度需等于10'
                raise ValueError(errmsg)
            name='_cardid'
        elif name == 'name':
            name='_name'
        elif name == 'age':
            if value<=0 or value>160:
                errmsg='年龄需大于0,小于等于160'
                raise ValueError(errmsg)
            name='_age'
        elif name == 'remain2retire':
            raise AttributeError('禁止修改')
        self.__dict__[name]=value
    def __str__(self):
        return PrintBusiCard().__str__(self)

>>> class BusiCardGetAtrriBute:
    '''
        实例访问全部属性被拦截
    '''
    cardidlen=10
    retireage=65
    def __init__(self,cardid,name,age,addr):
        self.cardid=cardid
        self.name=name
        self.age=age
        self.addr=addr
    def __getattribute__(self,name):
        objget=object.__getattribute__
        if name == 'cardid':
            return objget(self,'cardid')[:-5]+'*****'
        elif name == 'remain2retire':
            return objget(self,'retireage')-objget(self,'age')
        else:
            return objget(self,name)
    def __setattr__(self,name,value):
        if name == 'cardid':
            if len(str(value))!=self.cardidlen:
                errmsg='卡号长度需等于10'
                raise ValueError(errmsg)
        elif name == 'age':
            if value<=0 or value>160:
                errmsg='年龄需大于0,小于等于160'
                raise ValueError(errmsg)
        elif name == 'remain2retire':
            raise AttributeError('禁止修改')
        self.__dict__[name]=value
    def __str__(self):
        return PrintBusiCard().__str__(self)
        
>>> def testBC(BCDClass):
    print('当前BCDClass测试类为:'+BCDClass.__name__)
    bc1=BCDClass('1234567890','张三',39,'深圳')
    print(bc1)
    bc1.name='梯阅线条'
    bc1.age=33
    bc1.cardid='0123456789'
    print(bc1)
    bc2=BCDClass('0755123456','李四',21,'广州')
    print(bc2)
    try:
        bc2.age=211
    except ValueError as ve:
        print('年龄设置错误:'+str(ve))
    try:
        bc2.cardid='211'
    except ValueError as ve:
        print('卡号设置错误:'+str(ve))
    try:
        bc2.remain2retire=211
    except Exception as e:
        print('距离退休设置错误:'+str(e))

        
>>> for c in (BusiCardProp,BusiCardDesc,BusiCardGetAtrr,BusiCardGetAtrriBute):
    print('\n'+c.__name__.center(50,'='))
    testBC(c)


===================BusiCardProp===================
当前BCDClass测试类为:BusiCardProp
12345*****,张三,39,深圳,26
01234*****,梯阅线条,33,深圳,32
07551*****,李四,21,广州,44
年龄设置错误:年龄需大于0,小于等于160
卡号设置错误:卡号长度需等于10
距离退休设置错误:can't set attribute

===================BusiCardDesc===================
当前BCDClass测试类为:BusiCardDesc
12345*****,张三,39,深圳,26
01234*****,梯阅线条,33,深圳,32
07551*****,李四,21,广州,44
年龄设置错误:年龄需大于0,小于等于160
卡号设置错误:卡号长度需等于10
距离退休设置错误:禁止修改

=================BusiCardGetAtrr==================
当前BCDClass测试类为:BusiCardGetAtrr
12345*****,张三,39,深圳,26
01234*****,梯阅线条,33,深圳,32
07551*****,李四,21,广州,44
年龄设置错误:年龄需大于0,小于等于160
卡号设置错误:卡号长度需等于10
距离退休设置错误:禁止修改

===============BusiCardGetAtrriBute===============
当前BCDClass测试类为:BusiCardGetAtrriBute
12345*****,张三,39,深圳,26
01234*****,梯阅线条,33,深圳,32
07551*****,李四,21,广州,44
年龄设置错误:年龄需大于0,小于等于160
卡号设置错误:卡号长度需等于10
距离退休设置错误:禁止修改
文章来源:https://blog.csdn.net/sinat_34735632/article/details/135466749
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。