python描述符应用_python描述符应用

个人认为python中描述符协议是一个比较神奇的存在,是因为如果你不去了解property的内部实现,没有深究别人写的__set__、__get__方法。或许写python很多年都对这个东西没什么了解。然而这玩意儿有时候真的挺好用的。本文不会详述描述符协议。会着重讲一个小例子。如果以前没有接触过描述符,请依次查看文末相关资料的两篇文章

适用范围

描述符协议都是针对对象属性的访问。先要明白我们不会去针对一个全局的def使用property进行装饰。我们一般都是在类里面使用。可以对类的访问使用描述符(比较少用),更常用的是针对类实例的访问使用描述符协议

资料描述符和非资料描述符的区别1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23class (object):

def __get__(self, obj, objtype):

try:

return self.val

except:

return 'error'

# self.val = val

class MyClass(object):

x = RevealAccess()

m = MyClass()

print(m.x)

m.x = 20

print(m.__dict__)

m.__dict__['x'] = 1

print(m.__dict__)

print(m.x)

print(m.__class__ is type(m))

首先,当对属性x进行访问的时候不是直接返回描述符对象,而是按照描述符规则执行了描述符对象的_get_等方法!资料描述符就是同时实现了__get__和__set__,区别就是是资料描述符的时候就按照资料描述符的__get__、__set__来。非资料描述符的时候那就先访问`instance.__dict[‘x’]`,没有就在按照非资料描述符的__get__来。上面的例子先注释掉__set__就是非资料描述符,对实例属性进行访问的时候先访问了instance.__dict__没有就使用了描述符对象的__get__方法。当为资料描述符的时候纵然对instance.__dict__设置了。依然会调用描述符对象。

示例应用:property加强版,增加缓存(最简代码)

首先来一个例子1

2

3

4

5

6

7

8

9

10

11

12

13class Foo(object):

def jammy(self,_cache={}):

if 'result' in _cache:

return _cache['result']

print('jammy called')

result = 1

_cache.update({'result':result})

return result

f = Foo()

print(f.jammy)

print(f.jammy)

该方法使用python函数的默认参数只初始化一次对结果进行缓存。缺点比较明显。1.无法复用。2.对原函数进行了修改

下面看pyramid的实现1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18class reify(object):

def __init__(self, func):

self.func = func

def __get__(self, obj, cls):

value = obj.__dict__[self.func.__name__] = self.func(obj)

return value

class Foo(object):

@reify

def jammy(self):

print('jammy called')

return 1

f = Foo()

print(f.jammy)

print(f.jammy)

使用的是非资料描述符,第一次对属性进行访问的时候,因为f.__dict__是没有jammy的。故而访问了描述符,在描述符__get__里面将结果加入到了f.__dict__里面。后面访问就没__get__什么事儿了。实现了对结果的缓存

再看werkzeug的实现1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26class cached_property(property):

def __init__(self, func, name=None, doc=None):

self.__name__ = func.__name__

self.func = func

def __set__(self, obj, value):

obj.__dict__[self.__name__] = value

def __get__(self, obj, type=None):

value = obj.__dict__.get(self.__name__)

if value is None:

value = self.func(obj)

obj.__dict__[self.__name__] = value

return value

class Foo(object):

@cached_property

def jammy(self):

print('jammy called')

return 1

f = Foo()

print(f.jammy)

print(f.jammy)

可以看到和资料描述符的基本一样。可以看到__set__基本没什么用,仅仅只是表面了这是一个资料描述符。而且同样的,为了方便也一样把结果存储到了f.__dict__里面

_getattr_、__getattribute

虽然都有get,可是区别是很大的。

描述符是控制对象某个属性的访问(所以看到描述符对象一般主要用__get__,__get__)。

__getattr__它控制属性不存在的时候该咋办

__getattribute__和上面相反,默认行为,从__dict__中找到属性值返回1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16class Foo(object):

def __getattr__(self, attr):

print "looking up", attr

value = 42

self.__dict__[attr] = value

return value

f = Foo()

print f.x

print f.x

#output >>> looking up x 42

#output >>> 42

f.x = 3

print f.x

#output >>> 3

相关资料

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值