python内置的描述符

python有些内置的描述符对象,property、staticmethod、classmethod,python实现如下:

class Property(object):
def __init__(self,getf,setf,delf,doc):
self.getf=getf
self.setf=setf
self.delf=delf
self.doc=doc
def __get__(self,instance,own=None):
if instance is None:
return self
if self.getf is None:
raise AttributeError
return self.getf(instance)
def __set__(self,instance,value):
if self.setf is None:
raise AttributeError
self.setf(instance,value)
def __del__(self,instance):
if self.delf is None:
raise AttributeError
self.delf(instance)
class StaticMethod(object):
def __init__(self,func):
self.func=func
def __get__(self,instance,own=None):
return self.func
class ClassMethod(object):
def __init__(self,func):
self.func=func
def __get__(self,instance,own=None):
if own is None:
own=type(instance)
def callfunc(*args):
return self.func(own,*args)
return callfunc

为属性值设置别名

有时候你想用一个属性名作为另一个属性名的别名,比如设置一些属性的默认值必须和其他属性的当前值一样,而且还需要独立的设置和删除。

class DefaultAlias(object):
def __init__(self,name):
self.name=name
def __get__(self,instance,own):
if instance is None: #类属性访问时
return self
return getattr(instance,self.name).title()
class Person(object):
def __init__(self,name,aliasname=None):
self.name=name
if aliasname is not None:
self.aliasname=aliasname
aliasname=DefaultAlias('name')
>>> p=Person('sam')
>>> p.aliasname
'Sam'
>>> p.aliasname='jack'
>>> p.aliasname
'jack'
>>> del p.aliasname
>>> p.aliasname
'Sam'

这样就为属性name设置了一个别名aliasname,或者说把aliasname的值存储在了name中。DefaultAlias并不是数据描述符,因为它没有__set__方法,而是一个non-data描述符。所以我们给一个实例属性赋值时(p.aliasname='jack'),实例会正常地记录属性,而且实例属性会覆盖掉类属性。这样aliasname属性就能单独的设置而不影响name属性了。当我们del p.aliasname时,删除了实例的属性,类属性又会再次显现出来。

对于某些开发的类,如果要保持后续版本的兼容性,可以用新名称来命名方法和属性,同时保留旧名字的可用性。

class OldAlias(object):
def __init__(self,name,oldname):
self.name=name
self.oldname=oldname
def _warn(self):
print 'use %r,not %r'%(self.name,self.oldname)
def __get__(self,instance,own):
self._warn()
if instance is None:
return self
return getattr(instance,self.name)
def __set__(self,instance,value):
self._warn()
setattr(instance,self.name,value)
def __del__(self,instance):
self._warn()
delattr(instance,self.name)
class NewClass(object):
def __init__(self,newname):
self.newname=newname
oldname=OldAlias('newname','oldname')
>>> c=NewClass('a')
>>> c.oldname
use 'newname',not 'oldname'
'a'

使用这个类的旧代码会使用类属性oldname,同时一个警告信息被打印,鼓励用户使用新属性newname。

缓存属性值

根据需求计算实例属性或类属性的值,并提供自动化的缓存。

class CachedAttribute(object):
def __init__(self,method,name=None):
self.method=method
self.name=name if name else method.__name__
def __get__(self,instance,own):
if instance is None:
return self
result=self.method(instance)
setattr(instance,self.name,result)
return result
class MyObject(object):
def __init__(self,n):
self.n=n
@CachedAttribute
def square(self):
return self.n*self.n
>>> m=MyObject(2)
>>> m.square
4
>>> m.n=5
>>> m.square
4
>>> del m.square
>>> m.square
25

在首次访问m.square后,square属性就被缓存在实例m中,当改变实例属性n时,square属性不会改变。如果需要清除缓存,del m.square即可,再次访问m.square属性square的值会被再次计算。

缓存类属性:

class CachedClassAttribute(CachedAttribute):
def __get__(self,instance,own):
return super(CachedClassAttribute,self).__get__(own,own)
class MyClass(object):
class_attr=24
@CachedClassAttribute
def square(cls):
return cls.class_attr*cls.class_attr

这样类的所有实例都有同样的缓存值了:

>>> a=MyClass()
>>> b=MyClass()
>>> a.square
>>> print a.square
576
>>> print b.square
576
>>> print MyClass.square
576

  

python描述符descriptor(二)的更多相关文章

  1. Python 描述符(descriptor) 杂记

    转自:https://blog.tonyseek.com/post/notes-about-python-descriptor/ Python 引入的“描述符”(descriptor)语法特性真的很黄 ...

  2. python描述符descriptor(一)

    Python 描述符是一种创建托管属性的方法.每当一个属性被查询时,一个动作就会发生.这个动作默认是get,set或者delete.不过,有时候某个应用可能会有 更多的需求,需要你设计一些更复杂的动作 ...

  3. python描述符 descriptor

    descriptor 在python中,如果一个新式类定义了__get__, __set__, __delete__方法中的一个或者多个,那么称之为descriptor.descriptor通常用来改 ...

  4. python描述符(descriptor)、属性(property)、函数(类)装饰器(decorator )原理实例详解

     1.前言 Python的描述符是接触到Python核心编程中一个比较难以理解的内容,自己在学习的过程中也遇到过很多的疑惑,通过google和阅读源码,现将自己的理解和心得记录下来,也为正在为了该问题 ...

  5. Python描述符 (descriptor) 详解

    1.什么是描述符? python描述符是一个“绑定行为”的对象属性,在描述符协议中,它可以通过方法重写属性的访问.这些方法有 __get__(), __set__(), 和__delete__().如 ...

  6. Python 描述符(Descriptor) 附实例

    在 Python 众多原生特性中,描述符可能是最少被自定义的特性之一,但它在底层实现的方法和属性却无时不刻被使用着,它优雅的实现方式体现出 Python 简洁之美. 定义 一个描述符是一个有" ...

  7. Python 描述符 (descriptor)

    1.什么是描述符? 描述符是Python新式类的关键点之一,它为对象属性提供强大的API,你可以认为描述符是表示对象属性的一个代理.当需要属性时,可根据你遇到的情况,通过描述符进行访问他(摘自Pyth ...

  8. 【python】描述符descriptor

    开始看官方文档,各种看不懂,只看到一句Properties, bound and unbound methods, static methods, and class methods are all ...

  9. 杂项之python描述符协议

    杂项之python描述符协议 本节内容 由来 描述符协议概念 类的静态方法及类方法实现原理 类作为装饰器使用 1. 由来 闲来无事去看了看django中的内置分页方法,发现里面用到了类作为装饰器来使用 ...

随机推荐

  1. 解决DropDownList 有一个无效 SelectedValue,因为它不在项目列表中。这是怎么回事?

    产生错误原因: 绑定在DropDownList的时候 DropDownList没有对应的值 查了一下MSDN:DropDownList.SelectedValue 属性: 此属性返回选定的 ListI ...

  2. 如何从零开始实现一个soa远程调用服务基础组件

    说起soa远程调用基础组件,最著名的莫过于淘宝的dubbo了,目前很多的大型互联网公司都有一套自己的远程服务调用分布式框架,或者是使用开源的(例如dubbo),或者是自己基于某种协议(例如hessia ...

  3. Makefile当中宏定义传递字符串

    前几天遇到类似的问题[http://bbs.chinaunix.net/thread-1589386-1-1.html]: 在Makefile里面定义一个字符串在程序里面使用, CFLAGS += - ...

  4. 九度OJ 1499 项目安排 -- 动态规划

    题目地址:http://ac.jobdu.com/problem.php?pid=1499 题目描述: 小明每天都在开源社区上做项目,假设每天他都有很多项目可以选,其中每个项目都有一个开始时间和截止时 ...

  5. Android_时间服务

    接着上一节,这次我查看了Android的时间服务,觉得帮助很大,解决了我很多疑问,下面我就自己总结了一下,加深了自己的印象,好记性不如烂笔头,还真讲得很不错,收下吧?看下图如何利用线程更新UI组件 重 ...

  6. javascript 弹出的窗口返回值给 父窗口

    直接上代码,有些地方可以用到: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <H ...

  7. jQuery.ajax()的一些例子

    例子: Example: 保存数据到服务器,成功时显示信息. 1 2 3 4 5 6 7 $.ajax({ method: "POST", url: "some.php& ...

  8. jquery点击其他地方隐藏div层的实现程序

    js代码 $(document).ready(function() { //语言头部的点击事件,显示语言列表 $(".language_selected").click(funct ...

  9. 高性能IO设计的Reactor和Proactor模式(转)

    在高性能的I/O设计中,有两个比较著名的模式Reactor和Proactor模式,其中Reactor模式用于同步I/O,而Proactor运用于异步I/O操作. 在比较这两个模式之前,我们首先的搞明白 ...

  10. poj 2104 K-th Number 划分树,主席树讲解

    K-th Number Input The first line of the input file contains n --- the size of the array, and m --- t ...