Python自学成才之路 魔术方法之属性访问控制

Python中提供了一些魔术方法来控制对象属性的访问,赋值,删除过程。

属性访问魔术方法

__getattr__(self, item)
__getattribute__(self, item)

其中__getattr__只有在属性不存在时会被调用,__getattribute__无论属性是否存在都会被调用,item参数就是要访问的属性。

属性赋值魔术方法

__setattr__(self, key, value)

给对象属性赋值或者添加新属性时会被调用。

属性删除魔术方法

__delattr__(self, item)

当删除一个对象属性时,该方法会被调用。

下面通过一个案例来展示上面三个魔术方法的用法,其中age属性的值通过birth_date元素来计算出来的。


class Person(object):

    def __init__(self, name: str, birth_date: int):
        self.name = name
        self.birth_date = birth_date
        self.age = 0

    def __getattr__(self, item):
        raise AttributeError(item + "属性不存在")

    def __getattribute__(self, item):
        print("getattribute: %s" %item)
        return super(Person, self).__getattribute__(item)

    def __setattr__(self, key, value):
        print('__setattr__, key = %s, value = %s'%(key,value))
        if key == 'birth_date':
            super(Person, self).__setattr__('birth_date', value)
            super(Person, self).__setattr__('age', 2020 - value)
        else:
            # 必须加上这一步 否则所有的属性添加都会失败
            super(Person, self).__setattr__(key, value)

    def __delattr__(self, item):
        super(Person, self).__delattr__(item)
        print('delattr: %s'%item)


p1 = Person('peter', 2010)
print(p1.name)
print(p1.age)
p1.gender = 'man'
del p1.age
# 保证异常打印顺序
time.sleep(1)
print(p1.age)

输出:
__setattr__, key = name, value = peter
__setattr__, key = birth_date, value = 2010
__setattr__, key = age, value = 0
getattribute: name
peter
getattribute: age
0
__setattr__, key = gender, value = man
delattr: age
getattribute: age
Traceback (most recent call last):
  File "D:/pycharm workspace/oopdemo/magic_method/AttrDemo.py", line 89, in <module>
    print(p1.age)
  File "D:/pycharm workspace/oopdemo/magic_method/AttrDemo.py", line 61, in __getattr__
    raise AttributeError(item + "属性不存在")
AttributeError: age属性不存在

案例中__setattr__方法控制添加属性和给属性赋值的过程,通过birth_date属性来计算出age属性的值。

在使用这些访问控制魔术方法需要注意一点,不能通过self.xxx(备注:这里指的是访问控制魔术方法)的方式来访问,这样可能会导致死循环。比如把案例中的__getattribute__方法改成下面这样:


def __getattribute__(self, item):
    print("getattribute: %s" %item)
    return self.__getattribute__(item)

执行后会抛出RecursionError异常。RecursionError: maximum recursion depth exceeded while calling a Python object。

原因是self.__getattribute__会调用自身,所以就出现了死循环。通过supr(Person, self)来调用_XXX_(备注:这里指访问控制魔术方法)可以避免递归调用。

也有人通过self.__dict__的方式来访问或修改属性,这种方式看上去可行,但是存在一个问题,因为self.__dict__本身也是对象的属性(只是这个属性比较特殊,它存放了对象的其它属性),所以每次访问self.__dict__都会触发__getattribute__和__getattr__方法,这完全没必要,如果在这两个方法里面存在日志,会输出大量没必要的日志。所以建议通过supr(Person, self)来调用。




本人是做大数据开发的,在微信上开了个个人号,会经常在上面分享一些学习心得,原创文章都会首发到公众号上,感兴趣的盆友可以关注下哦!
在这里插入图片描述
备注:微信公众号搜索‘大数据入坑指南

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值