python之描述符

前言

感谢文章,python描述符。之前对这个东西一直是听说过但是不知道怎么回事,看了几篇文章也是不知道为什么有这样的设计,这篇文章看了之后算是基本上懂了,所以稍微记录一下自己的理解。

property

property是将函数调用伪装成对属性的访问,相信很多文章里边也提到这个说法了,我也只是照抄一下。关键是为什么?

为什么有property?

property将一个函数变成了类似于属性的使用,我可以很单纯的认为,无非只是省略了一个括号而已,可是这有什么意义? 那就是,我换一种方式来解释property的作用,那就是,以属性的方式来调用函数,换句话说,我以为我调用的是属性,但是其实是函数,这样,就完成了一个封装,不需要setter和getter,而直接将setter和getter内嵌进去,大大减少了代码量,使代码简洁美观。
一个示例

class MyClass(object):

    def __init__(self, data):
        try:
            if data >= 0:
                self._data = data
            else:
                raise ValueError("not a valid number")
        except ValueError:
            print ValueError.message

    def get_data(self):
        return self._data

    def set_data(self, data):
        try:
            if data >= 0:
                self._data = data
            else:
                raise ValueError("not a valid number")
        except ValueError:
            print ValueError.message


class MyNewClass(object):

    def __init__(self, data):
        try:
            if data >= 0:
                self._data = data
            else:
                raise ValueError
        except ValueError:
            print "not a valid number"

    @property
    def data(self):
        return self._data

    @data.setter
    def data(self, data):
        try:
            if data >= 0:
                self._data = data
            else:
                raise ValueError("not a valid number")
        except ValueError:
            print ValueError.message

两个class的作用其实是一样的,存储了一个非负的值。

但是明显第一种实现方式显得臃肿,而第二种就简介很多,使用时更是如此,第一种方法要求客户必须遵循其规则,由于没有强制数据为私有,如果不遵循规则,则可以存储为负的值,无论是使用方法还是安全性上都有所欠缺(其实可以将数据换为私有数据,提升安全性,但是使用上还是会臃肿,只能用java风格的set和get来存取数据)。

但是第二种则是使用了property,用这样的方法,存取只需要当做属性,也就是说,现在我对data这个属性的存取,相当于调用其setter方法和getter方法了。

property的问题?

当然这样的方法也不是完美的,如果很多属性都需要这样的存取,意味着需要写很多次,这样的话重复的过程太多。 本着将重复的过程集中的原则,拿出变化的,于是有了数据描述符的概念。

我们需要描述符

根据刚刚的问题,就有了描述符。我们将这些getter,setter重复的部分都放在一块,用描述符来处理。描述符,根据定义,其实是具有get,可以具有setdelete方法的类。

class Descriptor(object):

    def __init__(self):
        self._data = 0

    def __get__(self, instance, owner):
        return self._data

    def __set__(self, instance, data):
    #instance:
        try:
            if data >= 0:
                self._data = data
            else:
                raise ValueError("not a valid number")
        except ValueError:
            print ValueError.message

    def __delete(self, instance):
        del self._data


class MyClass(object):
    data = Descriptor()

这里MyClass中的data使用了这个描述符,以后对data的操作都将使用描述符中的set和get方法,当然del的时候也使用描述符中的delete方法了。这里的描述符由于同时具有set,get和delete的方法,所以称为数据描述符,如果只有get方法,称为非数据描述符,这里主要是区分属性的优先级。下面就来详细介绍。

三个方法

  • get(self, instance, owner) 也写作 get(self, obj, type).instance/obj是指调用的实例,type指调用的类。也就是说,x.foo在用描述符的时候,其实相当于调用type(x).__dict__["foo"].__get__(x,type(x))
  • set(self, instance, data)也写作 set(self, obj, data),data是要使用的值,instance/obj和get同义
  • delete(self, instance)或delete(self, obj),instance/obj与get,set同义

数据描述符/非数据描述符

前文已经提到,主要是用来在找属性的时候改变优先级。同时具有三个方法的为数据描述符,只有get的为非数据描述符,要是get都没有,为非描述符,额,我的意思是,压根不是个描述符=0=

优先级

python的属性优先级:
1.类属性
2.数据描述符
3.实例属性
4.非数据描述符
5.getattr(self, attr)方法,attr为属性名
如果需要优先级方面的详细解释参考

http://blog.csdn.net/imzoer/article/details/8788040

解决了property的问题

有了描述符,刚才property的问题就迎刃而解了,对于太多重复的property,将它们写作描述符,最后直接使用的描述符就好了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值