python对象之属性访问控制--descriptor
来源:互联网 发布:tensorflow能用java吗 编辑:程序博客网 时间:2024/05/16 15:57
在定义class时,会经常使用property、classmethod和staticmethod来定义属性,使属性具有特殊的访问功能。如下所示:
class Myclass(object): def func(self, str): print str def get_RMB(self): return self.mone*6 def set_dollar(self, value): self.mone=value def del_money(self): del self.mone money = myproperty(get_RMB, set_dollar, del_money, 'given dollars, get RMB') def clsfunc(cls,str): print 'clsfunc:',cls,str clsfunc = myclassmethod(clsfunc) def staticfunc(str): print 'staticfunc:',str staticfunc = mystaticmethod(staticfunc)
为什么它们能使属性的访问变得不同呢?答案在descriptor。上面的property、classmethod、staticmethod都是descriptor。
那什么是descriptor呢?
descriptor是一种实现__get__(), __set__(), __delete__()三个方法的class,所有实现这三个函数,并且支持特定参数的class都是descriptor。下面实现一个descriptor:
class Descriptor(object): def __get__(self, inst, cls): print '__get__', inst, cls def __set__(self, inst, value): print '__set__', inst, value def __delete__(self, inst): print '__del__', inst class A(object): des=Descriptor()
终端直接结果:
In [2]: a = A() In [3]: a.des __get__ <A object at 0x11eb9d0> <class 'A'> In [4]: a.des=1 __set__ <A object at 0x11eb9d0> 1 In [5]: del a.des __del__ <A object at 0x11eb9d0> In [7]: A.des __get__ None <class 'A'> In [8]: A.des=1 In [9]: del A.des
从上面的实验结果可知:1, 通过实例化对象a读取des时,执行的是descriptor的__get__()函数,传参为(a,A)
2, 给a.des赋值时,执行的是descriptor的__set__()函数,传参为(a,value)
3, 删除a.des时,执行的是descriptor的__delete__()函数,传参为(a)
4, 通过class访问时(A.des),与a.des一样,调用__get__()函数,不过传参为(None, A)
5, 设置和删除A.des时,不进行任何操作。
根据实现的接口不同,descriptor又可以分data descriptor和non-data descriptor。data descritor实现了__get__(), __set__(), __delete__()接口,而non-data descriptor只实现了__get__()。这两者的不同之处在于:设置和删除a.des时,data descriptor会调用__set__()和__delete__(), 而non-data descriptor表现与正常的对象属性一样,会被直接复制和删除。
有了上面的知识,我们就可以构造自己的property、classmethod、staticmethod了:
class property(object): def __init__(self, getter, setter=None, deller=None, doc=None): self.getter = getter self.setter = setter self.deller = deller self.__doc__ = doc def __get__(self, inst, cls): # for use class to access property if not inst: return self return self.getter(inst) def __set__(self, inst, value): if not self.setter: raise AttributeError('xxx') self.setter(inst, value) def __del__(self, inst): if not self.deller: raise AttributeError('xxx') self.deller(inst) class classmethod(object): def __init__(self, clsfunc): self.getter = clsfunc def __get__(self, inst, cls): def func(*arg, **kwargs): return self.getter(cls, *arg, **kwargs) return func class staticmethod(object): def __init__(self, staticfunc): self.getter=staticfunc def __get__(self, inst, cls): return self.getterclass Myclass(object): def func(self, str): print str def get_RMB(self): return self.mone*6 def set_dollar(self, value): self.mone=value def del_money(self): del self.mone money = myproperty(get_RMB, set_dollar, del_money, 'given dollars, get RMB') def clsfunc(cls,str): print 'clsfunc:',cls,str clsfunc = myclassmethod(clsfunc) def staticfunc(str): print 'staticfunc:',str staticfunc = mystaticmethod(staticfunc)
下面来分析一下,一般的成员函数,为什么在我们调用时候,第一个self不需要我们传入。
>>>dir(Myclass.__dict__['func'])['__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', '__dict__', '__doc__', '__format__', '__get__', #说明Myclass的func属性是一个Non-data descriptor '__getattribute__', '__globals__', '__hash__', '__init__', '__module__', '__name__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'func_closure', 'func_code', 'func_defaults', 'func_dict', 'func_doc', 'func_globals', 'func_name']>>>Myclass.__dict__['func']<function __main__.func>>>>Myclass.__dict__['func']('dd','hello') #此处可以看到,正常函数对参数的类型没有要求hello>>>Myclass.func<unbound method Myclass.func>>>>Myclass.func(Myclass(), 'hello') # 此处调用的func是descriptor的返回对象,它的第一个参数必须是Myclass的instance,否则会抛TypeErrorhello>>>Myclass().func<bound method Myclass.func of <__main__.Myclass object at 0x22a5410>>>>>Myclass().func('hello') #此处调用的func是descriptor的返回对象,它只需传递一个参数hello
上实验可知:
1 当通过Myclass.__dict__['func']调用时,它是一个正常的函数(同时也是一个non-data descriptor),不是descriptor的执行结果。
2 当通过Myclass.func调用时,它是func.__get__(None, Myclass)的返回对像(unbound method)
3 通过Myclass().func调用时,它是func.__get__(Myclass(),Myclass)的返回对象(bound method)
由此可知,class的一般成员函数,其实一个non-data descriptor,所以通过Myclass().func调用时,实际执行的该函数的__get__(),传参为(Myclass(), Myclass)。从而解释了为什么调用一般的成员函数时,无需传入self参数。
注意所有的函数都满足这个条件,而并非只在class内部的函数。
- python对象之属性访问控制--descriptor
- python对象之属性访问流程
- 对象之属性访问delete
- Python对象的属性访问过程
- 使用JS闭包控制对象属性访问范围
- python类:class创建、数据方法属性及访问控制
- python之Class属性定义和访问
- 面向对象程序设计之访问控制、继承与拷贝控制
- 访问控制属性
- Python descriptor
- python descriptor
- Python descriptor
- python descriptor
- python descriptor
- Python descriptor
- Python descriptor
- python对象:访问私有属性和私有方法
- 对象、访问控制符
- 一些算法面试题目
- Tomcat version 6.0 only supports J2EE 1.2, 1.3, 1.4, and Java EE 5 Web modules
- 每天写一点代码----完美字符串(庞果网)
- iPhone开发--问题 Not a PNG filCommand
- ubuntu 12.04安装jdk
- python对象之属性访问控制--descriptor
- 提高Java代码质量的Eclipse插件之Checkstyle的使用详解
- no such partition grub rescue的解决方案
- 【转】JAVA 验证代理是否可用
- 网络子系统69_路由表辅助程序
- ffmpeg windows安装
- 断言函数assert()与ASSERT()
- 关于分离线程
- 在从ArcGIS Server 9.x更新到ArcGIS Server 10后,日志在ArcGIS Server Manager中无法显示