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)来调用。
- 什么是编译错误,运行时错误及逻辑错误?
- 我的WCF之旅(4):WCF中的序列化[上篇]
- WCF技术剖析之二十八:自己动手获取元数据[附源代码下载]
- 微信年度重磅“小游戏”上线,罗胖一度退出的小程序正在逆袭
- 谈谈WCF中的Data Contract(2):WCF Data Contract对Generic的支持
- Android注解学习(1)
- [WCF权限控制]ASP.NET Roles授权[上篇]
- [WCF权限控制]ASP.NET Roles授权[下篇]
- 如何解决分布式系统中的跨时区问题[实例篇]
- Visual Studio对程序集签名时一个很不好用的地方
- 一个关于解决序列化问题的编程技巧
- [WCF权限控制]从两个重要的概念谈起:Identity与Principal[上篇]
- 从数据到代码——通过代码生成机制实现强类型编程[下篇]
- 谈谈你最熟悉的System.DateTime[下篇]
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Csharp实例:武汉智能安检闸机数据接收和解析
- [周末往期回顾]Oracle基本参数(LOG_ARCHIVE_DEST_n)
- [周末往期回顾]Oracle基本参数(SGA_TARGET)
- C#如何释放已经加载的图片
- 笔记本内置摄像头视频播放和存储
- [Data Guard全解析]5.Data Guard及ADG日常运维操作
- [Oracle 数据库日常操作] 表空间的日常运维命令
- Java 反射 -超详细讲解(附源码)
- [Data Guard全解析]6.物理备库的Switchover
- com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException异常解决方法
- [Oracle数据库日常操作] Redo Log的相关操作
- [周末往期回顾] 使用requests和fiddler模拟登陆51cto并获取下载币
- [周末往期回顾] 自动备份思科交换机配置
- [打造自己的监控系统]让Django运行自定义命令
- 没想到 Shell 命令竟然还能这么玩?| Shell 玩转大数据分析