python属性管理(1):基础
管理属性的几种方式
在python中访问、设置、删除对象属性的时候,有以下几种方式:
- 使用内置函数getattr()、setattr()和delattr()
- 自己编写
getter()、setter()、deleter()方法 - 重载
__getattr__()、__setattr__()、__delattr__()运算符,这决定了x.y的访问、赋值方式以及del x.y的方式 - 使用
__getattribute__()方法 - 使用描述符协议
- 使用property协议,它是一种特殊的描述符
本文简单介绍其中的前4种作为基础,后面使用单独的文章解释后2种。
内置函数XXXattr()管理属性
通过内置函数getattr()、setattr()、delattr()能简单访问、设置、删除对象上的属性。
先看看它们的帮助文档:
getattr(...)
getattr(object, name[, default]) -> value
Get a named attribute from an object;
getattr(x, 'y') is equivalent to x.y.
setattr(obj, name, value, /)
Sets the named attribute on the given object to the specified value.
setattr(x, 'y', v) is equivalent to ``x.y = v''
delattr(obj, name, /)
Deletes the named attribute from the given object.
delattr(x, 'y') is equivalent to ``del x.y''
用法很简单,给定要操作的对象obj以及要操作的属性名称name。对于getattr()来说,如果要操作的属性不存在默认会报错,可以给定一个default参数表示属性不存在时返回该给定属性值。
例如,下面是一个简单的Person类和对象p:
class Person():
def __init__(self, name):
self.name = name
p = Person("malongshuai")
使用getattr()获取name属性和不存在的age属性:
print(getattr(p, "name"))
print(getattr(p, "age", 23))
上面访问age属性时,如果把第三个参数"23"去掉,将抛出异常。
AttributeError: 'Person' object has no attribute 'age'
使用setattr()和delattr()设置和删除属性:
setattr(p, "age", 25)
print(p.__dict__)
delattr(p, "age")
print(p.__dict__)
返回结果:
{'name': 'malongshuai', 'age': 25}
{'name': 'malongshuai'}
自己编写accessor方法
一般面向对象的语言都是自己写setter、getter、deleter方法来管理属性的,通用又安全,但是管理起来并不那么方便。
这里仅介绍一下,它们更好的写法参考:python设置对象属性。
例如,在Person类中加上name、age这两个属性的accessor方法:
class Person():
def __init__(self, name):
self.name = name
def set_name(self,name): self.name = name
def get_name(self): return self.name
def del_name(self): del self.name
def set_age(self,age): self.age = age
def get_age(self): return self.age
def del_age(self): del self.age
缺点是很明显的,对于想要管理的每个属性,都得去定义这些属性。也就是说,accessor方法是针对单个属性的。
运算符重载管理属性
通常可以直接使用点号运算来访问、设置属性。例如:
p.name # (1)访问p对象的name属性
p.name = "abc" # (2)为p对象的name属性赋值
del p.name # (3)删除p对象的name属性
先说对象的赋值和删除操作,也就是上面的(2)和(3)。这两种操作可以直接被__setattr__()、__delattr__()这两个方法拦截,或者说只要重写了这两个方法,每当对属性赋值、删除时,都会调用对应的这两个方法。
再说访问属性的操作(1),python提供了两个对应的方法__getattr__()和__getattribute__()。前者是在访问不存在的属性时被自动调用的,后者则是访问属性时被调用的,它无视属性是否存在。
这里提前说一个稍后要遇到的问题总结:对于适用于所有属性操作的__setattr__、__delattr__和__getattribute__方法,要避免它们的无限递归。参考后面的示例即可知。
__getattr__()
__getattr__()是通过点号访问不存在属性时被调用的。它有两个使用标准:要么返回属性值,要么抛出异常。
例如:
class Person():
def __init__(self, name):
self.name = name
def __getattr__(self, attrname):
if attrname == "name":
print("in getattr1")
return self.name
elif attrname == "age":
print("in getattr2")
return 25
else:
print("in getattr3")
raise AttributeError(attrname)
p = Person("malongshuai")
上面的Person类带有属性name,所以访问name属性的时候不会调用__getattr__(),而访问age或其它属性时会调用该方法,只不过age属性有自定义的返回值,其它属性则报错。
print(p.name)
print(p.age)
print(p.job)
以下是输出结果:
malongshuai
in getattr2
25
in getattr3
Traceback (most recent call last):
File "g:/pycode/b.py", line 21, in <module>
print(p.job)
File "g:/pycode/b.py", line 14, in __getattr__
raise AttributeError(attrname)
AttributeError: job
__getattribute__()
__getattribute__()和__getattr__()类似,不同的是它前者适用于所有属性的访问,而不管目标属性是否存在。
需要注意的是,__getattribute__()适用于所有属性访问操作,所以要避免无限递归。例如,下面是错误的写法:
def __getattribute__(self, attr):
return self.attr
因为这个方法中的self.attr会继续触发__getattribute__的调用,从而出现无限递归问题。
解决办法是通过父类来访问,比如super()或object类。
super().__getattribute__(attr)
object.__getattribute__(self, attr)
__getattribute__()的优先级高于__getattr__(),前者存在的时候不会调用到后者,除非前者的代码中调用了后者,或者前者抛出了异常。
例如:
class Person():
def __init__(self, name):
self.name = name
def __getattribute__(self, attr):
print("in getattribute")
return object.__getattribute__(self, attr)
# return super.__getattribute__(attr)
def __getattr__(self, attrname):
if attrname == "name":
print("in getattr1")
return self.name
elif attrname == "age":
print("in getattr2")
return 25
else:
print("in getattr3")
raise AttributeError(attrname)
p = Person("malongshuai")
print(p.name)
print(p.age)
返回结果:
in getattribute
malongshuai
in getattribute
in getattr2
25
上面输出了name和age两个属性,但是输出"p.age"的时候该属性不存在,于是__getattribute__抛出异常,然后触发__getattr__。
需要注意的是,在解决无限递归问题上,后面的__setattr__和__delattr__还会有一种访问__dict__的方式,这不适合于这里的__getattribute__,因为访问这个字典也会触发__getattribute__从而继续导致无限递归。
__setattr__()
__setattr__()用来拦截对象属性赋值操作。例如:
p.name = "long"
会转换为调用p.__setattr__(self,name,"long")。
唯一需要注意的是避免赋值时的无限递归问题。因为在__setattr__()中的赋值语句self.attr = value会继续调用该方法,最终导致无限递归。
所以在__setattr__()方法中,必须使用__dict__来获取属性并进行赋值,或者访问父类同名属性。所以,有下面几种方式避免无限递归调用。
self.__dict__[attr] = value
super().__setattr__(attr, value)
object.__setattr__(self, attr, value)
参考下面的示例。
class Person():
def __init__(self, name):
self.name = name
def __setattr__(self, attr, value):
print("in setattr")
#self.__dict__[attr] = value
#super().__setattr__(attr, value)
object.__setattr__(self, attr, value)
p = Person("malongshuai")
p.age = 33 # 自动调用__setattr__()
print(p.age)
执行结果:
in setattr
in setattr
33
可能已经发现问题所在了,上面输出了两次in setter,原因是__init__()中的赋值操作也会触发__setattr__()。
__delattr__()
当调用del x.y的时候会自动触发__delattr__()的调用。
同样需要注意的是避免赋值时的无限递归问题。因为在__delattr__()中的del语句可能会继续调用该方法,最终导致无限递归。所以在__delattr__()方法中,必须使用__dict__来获取属性并进行赋值,或者访问父类同名属性。所以,有下面几种方式避免无限递归调用。
del self.__dict__[attr]
super().__delattr__(attr)
object.__delattr__(self, attr)
例如:
class Person():
def __init__(self, name):
self.name = name
def __delattr__(self, attr):
print("%s deleting" % (attr))
#del self.__dict__[attr]
#super().__delattr__(attr)
object.__delattr__(self, attr)
print("%s deleted" % (attr))
p = Person("malongshuai")
p.age = 33
del p.age
python属性管理(1):基础的更多相关文章
- Python中的属性管理
Python管 理属性的方法一般有三种:操作符重载(即,__getattr__.__setattr__.__delattr__和 __getattribute__,有点类似于C++中的重载操作符).p ...
- python对象属性管理(2):property管理属性
使用Property管理属性 python提供了一种友好的getter.setter.deleter类方法的属性管理工具:property. property()是一个内置函数,它返回一个Proper ...
- [读书]Python学习手冊--属性管理1
属性管理-特性 一般开发这不必关心属性的实现.对工具的构建这来说,了解这一块对API的灵活性有帮助. 大多数情况下,属性位于对象自身之中.或者继承自对象所派生自的一个类. ----python学习手冊 ...
- Python环境安装与基础语法(4)——内存管理、if分支
Python内存管理 python中有自动清理内存垃圾的功能,当变量的引用计数为0,则可以被有计划的垃圾回收GC 常量会在系统中被多次引用,所以常量的引用计数无法确定 程序控制 顺序:按照先后顺序逐条 ...
- python 小白(无编程基础,无计算机基础)的开发之路 day1
本节内容 Python介绍 发展史 Python 2 or 3? 安装 Hello World程序 变量 用户输入 模块初识 .pyc是个什么鬼? 数据类型初识 数据运算 表达式if ...else语 ...
- Python属性描述符(一)
描述符是对多个属性运用相同存取逻辑的一种方式,,是实现了特性协议的类,这个协议包括了__get__.__set__和__delete__方法.property类实现了完整的描述符协议.通常,可以只实现 ...
- Python进阶----数据库的基础,关系型数据库与非关系型数据库(No SQL:not only sql),mysql数据库语言基础(增删改查,权限设定)
day37 一丶Python进阶----数据库的基础,mysql数据库语言基础(增删改查,权限设定) 什么是数据库: 简称:DataBase ---->DB 数据库即存放数据的仓库, ...
- Python学习笔记之基础篇(-)python介绍与安装
Python学习笔记之基础篇(-)初识python Python的理念:崇尚优美.清晰.简单,是一个优秀并广泛使用的语言. python的历史: 1989年,为了打发圣诞节假期,作者Guido开始写P ...
- Python 包管理工具解惑
Python 包管理工具解惑 本文链接:http://zengrong.net/post/2169.htm python packaging 一.困惑 作为一个 Python 初学者,我在包管理上感到 ...
随机推荐
- Activiti工作流数据库表详细介绍
Activiti的后台是有数据库的支持,所有的表都以ACT_开头. 第二部分是表示表的用途的两个字母标识. 用途也和服务的API对应. ACT_RE_*: 'RE'表示repository. 这个前缀 ...
- Java 8 特性
1.简介 毫无疑问,Java 8是自Java 5(2004年)发布以来Java语言最大的一次版本升级,Java 8带来了很多的新特性,比如编译器.类库.开发工具和JVM(Java虚拟机).在这篇教程 ...
- 使用jquery实现文本框输入特效:文字逐个显示逐个消失反复循环
前两天看到某个网站上的输入框有个小特效:文字逐个显示,并且到字符串最大长度后,逐个消失,然后重新循环显示消失,循环显示字符串数组.我对这个小特效有点好奇,于是今天自己尝试用jquery写一个简单的小d ...
- logminer日志挖掘
参考自:https://blog.csdn.net/yes_is_ok/article/details/79296614 原文转自:http://blog.itpub.net/26736162/vie ...
- 用apache和tomcat搭建集群,实现负载均衡
型的企业应用每天都需要承受巨大的访问量,在着巨大访问量的背后有数台服务器支撑着,如果一台服务器崩溃了,那么其他服务器可以使企业应用继续运行,用户对服务器的运作是透明化的,如何实现这种透明化呢?由如下问 ...
- 【.NET Core项目实战-统一认证平台】第一章 功能及架构分析
[.NET Core项目实战-统一认证平台]开篇及目录索引 从本文开始,我们正式进入项目研发阶段,首先我们分析下统一认证平台应该具备哪些功能性需求和非功能性需求,在梳理完这些需求后,设计好系统采用的架 ...
- 2018年3月24日上海MVP线下技术交流活动简报
2018年3月24日下午,几位上海MVP自发组织了一次线下的技术交流会,主要由MVP胡浩牵头,我(陈晴阳).刘鑫.朱兴亮和胡浩各自做了一次主题演讲,具体主题是: 陈晴阳:<这还是我认识的Visu ...
- 在Apache上http强制跳转到https
https已经配置完成,也可以正常使用,但输入域名或http加域名时也一样可以打开网站,于是想强制使用https 大概百度了一下方法,感觉与之前设置二级域名绑定二级目录时差不多 首先,修改httpd. ...
- FTP服务器搭建
FTP 服务器架设: 关闭防火墙 service iptables stop 关闭SELinux setenforce 0 安装所需依赖及编译工具 yum install -y gcc openssl ...
- PDF 报表 Java 组件 iText5 中的单位注意事项
这里面涉及到这几个单位: 点(磅)(pt).像素(px).英寸(inch).毫米(mm) 分辨率单位有: dpi(点每英寸):出现于打印或印刷领域. lpi (线每英寸):描述光学分辨率的尺度. pp ...