前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >Python自学成才之路 魔术方法之属性访问控制

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

作者头像
我是李超人
发布2020-08-20 16:53:50
发布2020-08-20 16:53:50
54700
代码可运行
举报
运行总次数:0
代码可运行

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

属性访问魔术方法

代码语言:javascript
代码运行次数:0
运行
复制
__getattr__(self, item)
__getattribute__(self, item)

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

属性赋值魔术方法

代码语言:javascript
代码运行次数:0
运行
复制
__setattr__(self, key, value)

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

属性删除魔术方法

代码语言:javascript
代码运行次数:0
运行
复制
__delattr__(self, item)

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

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

代码语言:javascript
代码运行次数:0
运行
复制
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__方法改成下面这样:

代码语言:javascript
代码运行次数:0
运行
复制
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)来调用。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020/08/13 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档