python描述符descriptor(二)

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 __set__(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.nm
>>> 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):
        super(CachedClassAttribute,self).__get__(own,owna=)
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(二),布布扣,bubuko.com

时间: 2024-12-25 08:13:17

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

python描述符descriptor(一)

Python 描述符是一种创建托管属性的方法.每当一个属性被查询时,一个动作就会发生.这个动作默认是get,set或者delete.不过,有时候某个应用可能会有 更多的需求,需要你设计一些更复杂的动作.最好的解决方案就是编写一个执行符合需求的动作的函数,然后指定它在属性被访问时运行.一个具有这种功能的对象 称为描述符.描述符是python方法,绑定方法,super,property,staticmethod和classmethod的实现基础. 1.描述符协议 描述符descriptor就是一个表

Python 描述符(descriptor) 杂记

转自:https://blog.tonyseek.com/post/notes-about-python-descriptor/ Python 引入的“描述符”(descriptor)语法特性真的很黄很暴力,我觉得这算是 Python 对象模型的核心成员之一.Python 语言设计的紧凑很大程度上得益于它.所以写一篇笔记文记录关于描述符我知道的一切. 低层 - 纯纯的描述符 纯纯的描述符很纯,基于类中定义的 __get__ . __set__ . __delete__ 三个特殊的方法.实现了这三

python描述符 descriptor

在python中,如果一个新式类定义了__get__, __set__, __delete__方法中的一个或者多个,那么称之为descriptor.descriptor通常用来改变默认的属性访问(attribute lookup), 前提是descriptor的实例是类的属性(class attribute).下面的代码展示了简单的用法  1 # -*- coding: utf-8 -*- 2 class Des(object): 3     def __init__(self, init_va

杂项之python描述符协议

杂项之python描述符协议 本节内容 由来 描述符协议概念 类的静态方法及类方法实现原理 类作为装饰器使用 1. 由来 闲来无事去看了看django中的内置分页方法,发现里面用到了类作为装饰器来使用,由于之前就看到过这一类的用法,但是一直没有明白具体是如何实现的,今天本着打破砂锅问到底的精神去网上搜资料,在这里不得不吐槽下百度搜索的垃圾了.....竞价排名做的那么6,搜一些技术文档.....各种坑爹...就是找不到想要的资源...于是FQ上google搜了搜,找到了python官网的文档...

转载python描述符介绍

来源:http://www.ibm.com/developerworks/cn/opensource/os-pythondescriptors/ 简介 Python 2.2 引进了 Python 描述符,同时还引进了一些新的样式类,但是它们并没有得到广泛使用.Python 描述符是一种创建托管属性的方法.除了其他优点外,托管属性还用于保护属性不受修改,或自动更新某个依赖属性的值. 描述符增加了对 Python 的理解,改善了编码技能.本文介绍了描述符协议,并演示了如何创建和使用描述符. 描述符协

Iterator Protocol - Python 描述符协议

1 Iterator Protocol - Python 描述符协议 2 3 先看几个有关概念, 4 iterator 迭代器, 5 一个实现了无参数的 __next__ 方法, 并返回 '序列'中下一个元素,在没有更多的元素可返回的时候 raises StopIteration 的对象, 6 被称为 iterator(迭代器). 7 在 python 中, 迭代器 'iterator' 同时也实现了 __iter__ 方法, 故 iterators are iterable. 8 经典迭代器

python——描述符

1.什么是描述符? python描述符是一个“绑定行为”的对象属性,在描述符协议中,它可以通过方法重写属性的访问.这些方法有 __get__(), __set__(), 和__delete__().如果这些方法中的任何一个被定义在一个对象中,这个对象就是一个描述符. 2.讲解描述符前,先看一下属性:__dict__ (每个对象均具备该属性) 作用:字典类型,存放本对象的属性,key(键)即为属性名,value(值)即为属性的值,形式为{attr_key : attr_value} 对象属性的访问

Python描述符的使用

Python描述符的使用 前言 作为一位python的使用者,你可能使用python有一段时间了,但是对于python中的描述符却未必使用过,接下来是对描述符使用的介绍 场景介绍 为了引入描述符的使用,我们先设计一个非常简单的类: class Product(): def __init__(self,name,quantity,price): self.name = name self.quantity = quantity self.price = price 这是一个商品类,存储该商品的名称

Python属性描述符(二)

Python存取属性的方式特别不对等,通过实例读取属性时,通常返回的是实例中定义的属性,但如果实例未曾定义过该属性,就会获取类属性,而为实例的属性赋值时,通常会在实例中创建属性,而不会影响到类本身.这种不对等的方式对描述符类也有影响. def cls_name(obj_or_cls): # 传入一个实例,返回类名 cls = type(obj_or_cls) if cls is type: cls = obj_or_cls return cls.__name__.split('.')[-1] d