pythonproperty原理_Python中 property 的实现原理及实现纯 Python 版

起步

property 是 Python 内置的功能,常用来修饰类方法,用于已访问属性的方式调用函数。

class C(object):

def __init__(self):

self._x = 'Tom'

@property

def x(self):

return self._x

@x.setter

def x(self, value):

self._x = value

c = C()

print(c.x) # Tom

c.x = 'Tony'

print(c.x) # Tony

尽管 property 的实现是 C 实现,但仍不妨碍探究它的实现原理,本文最后也会给出它的纯 Python 版本的实现。

描述符对象

为了能够实现访问属性就调用某个函数,这里将利用 描述符对象 作为本文的实现起点,当某个类定义了 __get__ 方法后,通过其方法名称可以直接调用 __get__ ,例如:

class Desc:

def __init__(self, name):

self.name = name

def __get__(self, obj, objtype):

print('Retrieving', self.name)

return self.name

class A:

x = Desc('Tom')

a = A()

print(a.x) # 打印了 'Retrieving'

从这点来看,如果我们自行实现 property ,那它将会是类而不是函数,同样的为了能够完成属性的赋值操作,该类还要设置 __set__ 函数。

setter 函数的实现

这个的实现需要脑子转个弯。对于修饰符 @x.setter ,因为 x 已经是 property() 的实例,所以我们要完成的 property 要实现 setter 函数,那函数体会是什么呢?

函数体也是要返回描述符对象,并该对象是有 __set__ 的。那 property 不就正好满足吗,所以这里的处理方式是 setter 函数会返回一个新的 property 实例。

property 的简易实现

基于上述分析,对于开头中的实例代码可运行的简易版本:

class property:

def __init__(self, fget=None, fset=None):

self.fget = fget

self.fset = fset

def __get__(self, inst, owner=None):

if inst is None:

return self

return self.fget(inst)

def __set__(self, inst, value):

self.fset(inst, value)

def setter(self, fset):

return property(self.fget, fset)

property 的完整实现

这个基本是依据 C 实现的纯 Python 版本,纯 C 实现在文件 Objects/descrobject.c 中。

Python 实现版本:

class property:

"Emulate PyProperty_Type() in Objects/descrobject.c"

def __init__(self, fget=None, fset=None, fdel=None, doc=None):

self.fget = fget

self.fset = fset

self.fdel = fdel

if doc is None and fget is not None:

doc = fget.__doc__

self.__doc__ = doc

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

if obj is None:

return self

if self.fget is None:

raise AttributeError("unreadable attribute")

return self.fget(obj)

def __set__(self, obj, value):

if self.fset is None:

raise AttributeError("can't set attribute")

self.fset(obj, value)

def __delete__(self, obj):

if self.fdel is None:

raise AttributeError("can't delete attribute")

self.fdel(obj)

def getter(self, fget):

return type(self)(fget, self.fset, self.fdel, self.__doc__)

def setter(self, fset):

return type(self)(self.fget, fset, self.fdel, self.__doc__)

def deleter(self, fdel):

return type(self)(self.fget, self.fset, fdel, self.__doc__)

在创建新的 proptery 实例中使用的是 type(self)(...) ,这是因为考虑到了 proptery 可能被继承。

总结

proptery 主要依赖于描述符的机制。proptery 内置也成为了 Python 的一个特性,它的内部实现原理很简单,但在应用上却很方面,可读性也十分友好。

参考https://docs.python.org/3/howto/descriptor.html​docs.python.org

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值