Python——管理属性(2)
__getattr__和__getattribute__
眼下已经介绍了特性property和描写叙述符来管理特定属性【參考这里】,而__getattr__和__getattribute__操作符重载方法提供了拦截类实例的属性获取的还有一种方法。它们有更广泛的应用,但是它们的表现并不同:
【1】__getattr__针对没有定义的属性执行——也就是说,属性没有存储在实例上,或者没有从其类之中的一个继承。
【2】__getattribute__针对每一个属性。因此,当使用它的时候,必须小心避免通过把属性訪问传递给超类而导致递归循环。
这两个方法是一组属性拦截方法的代表。这些方法还包含__setattr__和__delattr__,作用也一样。
与特性和描写叙述符不同,这些方法是Python【操作符重载】协议的一部分——是类的特殊命名的方法,由子类继承。
__getattr__和__getattribute__方法也比特性和描写叙述符通用。用于拦截差点儿全部的实例属性的获取,而不不过特定名称。因此,这两个方法适合于通用的基于托付的编码方式。
----------------------------------------------------------------------------------------------------------------------------------------
基础知识
假设一个类定义了或继承了例如以下方法,那么当一个实例用于后面的凝视所提到的情况时。它们将自己主动执行:
def __getattr__(self,name): # 引用实例没有定义的属性obj.name
def __getattribute(self,name): # 引用全部属性obj.name
def __setattr__(self,name,value): # 设置不论什么属性obj.name = value
def __delattr__(self,name,value): # 删除不论什么属性del obj.name
全部这些中。self一般是主体实例对象,name是将要訪问的属性的字符串名。value是将要赋给该属性的对象。两个get方法通常返回一个属性的值,另两个方法返回None。比如,要捕获每一个属性的获取,我们能够使用上面的两个方法,要捕获属性赋值,能够使用第三个方法:
>>> class Catcher:
def __getattr__(self,name):
print('Get:',name)
def __setattr__(self,name,value):
print('Set:',name,value) >>> X = Catcher()
>>> X.job
Get: job
>>> X.pay
Get: pay
>>> X.pay = 99
Set: pay 99
----------------------------------------------------------------------------------------------------------------------------------------
避免属性拦截方法中的循环
使用这些方法要避免潜在的递归循环。
比如,在一个__getattribute__方法代码内部的还有一次属性获取。将会再次触发__getattribute__,而且代码将会循环知道内存耗尽:
def __getattribute__(self,name):
x = self.other
要解决问题,把获取指向一个更高的超类,而不是跳过这个层级的版本号——object类总是一个超类,而且它在这里能够非常好的起作用:
def __getattribute__(self,name):
x = object.__getattribute__(self,'other')
对于__setattr__,情况是类似的,在这种方法内赋值不论什么属性,都会再次触发__setattr__并创建一个类似的循环:
def __setattr__(self,name,value):
self.other = value
要解决问题。把属性作为实例的__dict__命名空间字典中的一个键赋值。这样就避免了直接的属性赋值:
def __setattr__(self,name,value):
self.__dict__['other'] = value
另一种不经常使用的方法,__setattr__也能够把自己的属性赋值传递给一个更高的超类而避免循环,就像__getattribute__一样:
def __setattr__(self,name,value):
object.__setattr__(self,'other',value)
相反,我们不能使用__dict__技巧在__getattribute__中避免循环:
def __getattribute__(self,name):
x = self.__dict__['other']
由于获取__dict__属性会再次触发__getattribute__,从而导致递归循环。
----------------------------------------------------------------------------------------------------------------------------------------
演示样例
这里是与特性和描写叙述符一样的演示样例,只是是用属性操作符重载方法实现的。
class Person:
def __init__(self,name):
self._name = name def __getattr__(self,attr):
if attr == 'name':
print('fetch...')
return self._name
else:
raise AttributeError(attr) def __setattr__(self,attr,value):
if attr == 'name':
print('change...')
attr = '_name'
self.__dict__[attr] = value def __delattr__(self,attr):
if attr == 'name':
print('remove...')
attr = '_name'
del self.__dict__[attr] bob = Person('Bob Smith')
print(bob.name)
bob.name = 'Robert Smith'
print(bob.name)
del bob.name print('-'*20)
sue = Person('Sue Jones')
print(sue.name)
#print(Person.name.__doc__) #这里没有与特性等同的使用方法
注意,__init__构造函数中的属性赋值也触发了__setattr__。这种方法捕获了每次属性赋值,即便是类自身之中的那些。
执行这段代码,会产生相同的输出:
fetch...
Bob Smith
change...
fetch...
Robert Smith
remove...
--------------------
fetch...
Sue Jones
还要注意,与特性和描写叙述符不同,这里没有为属性直接声明指定的文档。
要实现与__getattribute__同样的结果,用以下的代码替换演示样例中的__getattr__,因为它会捕获全部的属性获取,所以必须通过把新的获取传递到超类来避免循环:
def __getattribute__(self,attr):
if attr == 'name':
print('fetch...')
attr = '_name'
return object.__getattribute__(self,attr)
这些样例尽管与特性和描写叙述符编写的代码一致,可是它并没有强调这些工具的用处。因为它们是通用的。所以__getattr__和__getattribute__在基于托付的代码中更为经常使用。而在仅仅有单个的属性要惯例的情况下,使用特性和描写叙述符更好。
Python——管理属性(2)的更多相关文章
- Python——管理属性(1)
		
管理属性 这里将展开介绍前面提到的[属性拦截]技术.包含下面内容: [1]__getattr__和__setattr__方法.把没有定义的属性获取和全部的属性赋值指向通用的处理器方法 [2]__get ...
 - python对象属性管理(2):property管理属性
		
使用Property管理属性 python提供了一种友好的getter.setter.deleter类方法的属性管理工具:property. property()是一个内置函数,它返回一个Proper ...
 - 使用Python管理数据库
		
使用Python管理数据库 这篇文章的主题是如何使用Python语言管理数据库,简化日常运维中频繁的.重复度高的任务,为DBA们腾出更多时间来完成更重要的工作.文章本身只提供一种思路,写的不是很全 ...
 - 使用 python 管理 mysql 开发工具箱 - 1
		
Mysql 是一个比较优秀的开源的数据库,很多公司都在使用.作为运维人员,经常做着一些重复性的工作,比如创建数据库实例,数据库备份等,完全都可以使用 python 编写一个工具来实现. 一.模块 Co ...
 - python 类属性与方法
		
Python 类属性与方法 标签(空格分隔): Python Python的访问限制 Python支持面向对象,其对属性的权限控制通过属性名来实现,如果一个属性有双下划线开头(__),该属性就无法被外 ...
 - python 类属性和实例属性
		
class AAA(): aaa = 10 # 情形1 obj1 = AAA() obj2 = AAA() print obj1.aaa, obj2.aaa, AAA.aaa # 情形2 obj1.a ...
 - 【转】spring管理属性配置文件properties——使用PropertiesFactoryBean|spring管理属性配置文件properties——使用PropertyPlaceholderConfigurer
		
spring管理属性配置文件properties--使用PropertiesFactoryBean 对于属性配置,一般采用的是键值对的形式,如:key=value属性配置文件一般使用的是XXX.pr ...
 - SpringCloud的Archaius - 动态管理属性配置
		
参考链接:http://www.th7.cn/Program/java/201608/919853.shtml 一.Archaius是什么? Archaius用于动态管理属性配置文件. 参考自Gett ...
 - python类属性和类方法(类的结构、实例属性、静态方法)
		
类属性和类方法 目标 类的结构 类属性和实例属性 类方法和静态方法 01. 类的结构 1.1 术语 —— 实例 使用面相对象开发,第 1 步 是设计 类 使用 类名() 创建对象,创建对象 的动作有两 ...
 
随机推荐
- PHP生成RSS报
			
<?php$sql="select * from wx_zimi ";$res=$dbs->query($sql);$arr=array();while($o=$dbs ...
 - [置顶]
        Docker学习总结(1)——Docker实战之入门以及Dockerfile(一)
			
一.Docker是什么? 首先Docker是软件工业上的集装箱技术 回顾,在没有集装箱出现以前,传统运输行业中,会存在这些问题: 在运输过程中,货物损坏 装卸.运输货物,效率低下 运输手续繁多及运输环 ...
 - SDNU 1206.蚂蚁感冒 【代码如此简单,思维练习】【7月29】
			
蚂蚁感冒 Description 长100厘米的细长直杆子上有n仅仅蚂蚁. 它们的头有的朝左,有的朝右. 每仅仅蚂蚁都仅仅能沿着杆子向前爬,速度是1厘米/秒. 当两仅仅蚂蚁碰面时.它们会同一时候掉头往 ...
 - google 分屏 横屏模式 按home键界面错乱故障分析(二) 分屏的启动过程
			
google 进入分屏后在横屏模式按home键界面错乱(二) 你确定你了解分屏的整个流程? imageMogr2/auto-orient/strip%7CimageView2/2/w/1240&quo ...
 - 修改android的wifi客户端名称的两种方法
			
修改android的wifi客户端名称的两种方法 手机连接到无线路由时,在dhcp的客户端列表里面是这样的名称"android-89425253e5de3a2",这就是安卓 ...
 - dump var_dump print print_r的区别
			
dump var_dump print print_r的区别 一.总结 用dump()来打印就对了 1.echo和print:不能打印复合型和资源型数据: 2.var_dump()和print_r() ...
 - Python 标准库 csv —— csv 文件的读写
			
csv 文件,逗号分割文件. 0. 读取 csv 到 list from csv import reader def load_csv(csvfile): dataset = [] with open ...
 - gulp几个常见问题及解决方案
			
1. 找不到local gulp 报错代码: $ gulp [23:29:31] Local gulp not found in [23:29:31] Try running: npm install ...
 - 关于Webpack详述系列文章 (第二篇)
			
1.缩小文件搜索范围 1.1.1 include & exclude module:{ rules:[ { test:/\.js$/, use:['babel-loader?cacheDire ...
 - 解决eclipse端口被占用的问题
			
问题如图所示,在eclipse中开启tomcat服务器时报错:端口已被占用. 这是因为在tomcat开启的状态下,eclipse异常关闭,导致tomcat一直占用端口. 解决办法如下: 1: 输入命令 ...