`

Python学习笔记——描述符

 
阅读更多

在Python中,访问一个属性的优先级顺序按照如下顺序:

  1. 类属性
  2. 数据描述符
  3. 实例属性
  4. 非数据描述符
  5. __getattr__()方法 这个方法的完整定义如下所示:
def __getattr(self,attr) :#attr是self的一个属性名
     pass;

先来阐述下什么叫数据描述符。

数据描述符是指实现了__get__,__set__,__del__方法的类属性(由于Python中,一切皆是对象,所以你不妨把所有的属性也看成是对象)

PS:个人觉得这里最好把数据描述符等效于定义了__get__,__set__,__del__三个方法的接口。

阐述下这三个方法:

__get__的标准定义是__get__(self,obj,type=None),它非常接近于JavaBean的get

第一个函数是调用它的实例,obj是指去访问属性所在的方法,最后一个type是一个可选参数,通常为None(这个有待于进一步的研究)

例如给定类X和实例x,调用x.foo,等效于调用:

type(x).__dict__["foo"].__get__(x,type(x))

调用X.foo,等效于调用:

type(x).__dict__["foo"].__get__(None,type(x))

第二个函数__set__的标准定义是__set__(self,obj,val),它非常接近于JavaBean的set方法,其中最后一个参数是要赋予的值

第三个函数__del__的标准定义是__del__(self,obj),它非常接近Java中Object的Finailize()方法,指Python在回收这个垃圾对象时所调用到的析构函数,只是这个函数永远不会抛出异常。因为这个对象已经没有引用指向它,抛出异常没有任何意义。

接下来,我们来一一比较这些优先级.

首先来看类属性

class A(object):
    foo=1.3;
     
print str(A.__dict__);

输出:

{"__dict__": <attribute "__dict__" of "A" objects>, "__module__": "__main__",
 "foo": 1.3, "__weakref__":  <attribute "__weakref__" of "A" objects>, "__doc__": None}

从上图可以看出foo属性在类的__dict__属性里,所以这里用A.foo可以直接找到。这里我们先跨过数据描述符,直接来看实例属性。

class A(object):
    foo=1.3;
 
a=A();
print a.foo;
a.foo=15;
print a.foo; 

这里a.foo先输出1.3后输出15,不是说类属性的优先级比实例属性的优先级高吗?按理a.foo应该不变才对?其实,这里只是一个假象,真正的原因在于这里将a.foo这个引用对象,不妨将其理解为可以指向任意数据类型的指针,指向了15这个int对象。

不信,可以继续看:

class A(object):
    foo=1.3;
 
a=A();
print a.foo;
a.foo=15;
print a.foo;
del a.foo;
print a.foo; 

这次在输出1.3,15后最后一次又一次的输出了1.3,原因在于a.foo最后一次又按照优先级顺序直接找到了类属性A.foo

然后我们来看下数据描述符这一全新的语言概念。按照之前的定义,一个实现了__get__,__set__,__del__的类都统称为数据描述符。我们来看下一个简单的例子。

    
class simpleDescriptor(object):
   def __get__(self,obj,type=None) :
       pass;
   def __set__(self,obj,val):
       pass;
   def __del__(self,obj):
       pass
     
class A(object):
    foo=simpleDescriptor();
print str(A.__dict__);
print A.foo;
a=A();
print a.foo;
a.foo=13;
print a.foo;

这里get,set,del方法体内容都略过,虽然简单,但也不失为一个数据描述符。让我们来看下它的输出:

{"__dict__":  <attribute "__dict__" of "A" objects >, "__module__": "__main__",
"foo":  <__main__.simpleDescriptor object at 0x00C46930 >,
"__weakref__":  <attribute "__weakref__" of "A" objects >,
"__doc__": None}
None
None
None

从上图可以看出,尽管我们对a.foo赋值了,但其依然为None,原因就在于__get__方法什么都不返回。

为了更进一步的加深对数据描述符的理解,我们简单的作下改造。

class simpleDescriptor(object):
    def __init__(self):
        self.result=None;
    def __get__(self,obj,type=None) :
        return self.result-10;
    def __set__(self,obj,val):
        self.result=val+3;
        print self.result;
    def __del__(self,obj):
        pass
     
class A(object):
    foo=simpleDescriptor();
a=A();
a.foo=13;
print a.foo;

打印的输出结果为:

16
6

第一个16为我们在对a.foo赋值的时候,人为的将13加上3后作为foo的值,第二个6是我们在返回a.foo之前人为的将它减去了10。

所以我们可以猜测,常规的Python类在定义get,set方法的时候,如果无特殊需求,直接给对应的属性赋值或直接返回该属性值。如果自己定义类,并且继承object类的话,这几个方法都不用定义。

下面我们来看下实例属性和非数据描述符。

class B(object):
    foo=1.3;
b=B();
print b.__dict__
#print b.bar;
b.bar=13;
print b.__dict__
print b.bar;
输出结果为: {} {"bar": 13} 13

可见这里在实例b.__dict__里找到了bar属性,所以这次可以获取13了。

那么什么是非数据描述符呢?简单的说,就是没有实现get,set,del三个方法的所有类

让我们任意看一个函数的描述:

def hello():
    pass
 
print dir(hello)

输出:

["__call__", "__class__", "__delattr__", "__dict__",
"__doc__",
"__get__",
"__getattribute__",
"__hash__", "__init__", "__module__", "__name__",
 "__new__", "__reduce__",
"__reduce_ex__", "__repr__",
 "__setattr__", "__str__", "func_closure",
"func_code",
"func_defaults", "func_dict", "func_doc", "func_globals", "func_name"]

从上面可以看出所有的函数都有get方法,但都没有set和del方法,所以所有的类成员函数都是非数据描述符。

看一个简单的例子:

class simpleDescriptor(object):   
    def __get__(self,obj,type=None) :
        return "get",self,obj,type;
class D(object):
    foo=simpleDescriptor();
d=D();
print d.foo;
d.foo=15;
print d.foo;

输出:

("get",  <__main__.simpleDescriptor object at 0x00C46870 >,
 <__main__.D object at 0x00C46890 >,  <class "__main__.D" >)
15

可以看出实例属性掩盖了非数据描述符。

最后看下__getatrr__方法。它的标准定义是:__getattr__(self,attr),其中attr是属性名

让我们来看一个简单的例子:

class D(object):
    def __getattr__(self,attr):
        return attr;
        #return self.attr;
         
d=D();
print d.foo,type(d.foo);
d.foo=15;
print d.foo;

输出:

foo <type "str" >
15

可以看的出来Python在实在找不到方法的时候,就会求助于__getattr__方法。这有点像javascript中FF的私有实现__noSuchMethod__,或ruby中的method_missing.

注意这里要避免无意识的递归,稍微改动下:

   
class D(object):
    def __getattr__(self,attr):
        #return attr;
        return self.attr;
         
d=D();
print d.foo,type(d.foo);
d.foo=15;
print d.foo;

这次会直接抛出堆栈溢出的异常,就像下面这样:

RuntimeError: maximum recursion depth exceeded
 
 
 
标签: python
分享到:
评论

相关推荐

    Python 笔记源码——内含python后端&机器学习等.zip

    Python 笔记源码——内含python后端&机器学习等.zip Python 笔记源码——内含python后端&机器学习等.zip Python 笔记源码——内含python后端&机器学习等.zip Python 笔记源码——内含python后端&机器学习等.zip ...

    Python学习笔记——运算符

    Python学习笔记——运算符 运算符: 赋值运算符 算术运算符 关系运算符 逻辑运算符 位运算

    Python学习笔记——输入input()

    Python学习笔记——输入input(),input()使用,两个练习。

    Python学习笔记——socket通信相关资源文件

    本篇笔记将深入探讨Python中的socket通信,并结合提供的资源文件进行讲解。 首先,让我们了解什么是socket。Socket是操作系统为网络通信提供的一种接口,可以理解为两台计算机之间通信的通道。在Python中,我们可以...

    python小游戏——扫雷

    python小游戏——扫雷

    python项目——智慧校园考试系统.zip

    python项目——智慧校园考试系统.zip python项目——智慧校园考试系统.zip python项目——智慧校园考试系统.zip python项目——智慧校园考试系统.zip python项目——智慧校园考试系统.zip python项目——智慧校园...

    Python深度学习实战——基于Pytorch全书电子教案完整版ppt整套教学课件最全教学教程.pptx

    Python深度学习实战——基于Pytorch全书电子教案完整版ppt整套教学课件最全教学教程.pptx

    python项目——Word助手.zip

    python项目——Word助手.zip python项目——Word助手.zip python项目——Word助手.zip python项目——Word助手.zip python项目——Word助手.zip python项目——Word助手.zip python项目——Word助手.zip python项目...

    Word版,Python GUI设计——Tkinter菜鸟编程(上、中、下)

    ### Python GUI设计——Tkinter基础知识详解 #### 一、Tkinter简介 Tkinter是Python标准库中的一个图形用户界面(GUI)工具包,它提供了一系列的控件来帮助开发者快速构建用户界面。由于其易用性和跨平台特性,...

    python项目——DIY字符画.zip

    python项目——DIY字符画.zip python项目——DIY字符画.zip python项目——DIY字符画.zip python项目——DIY字符画.zip python项目——DIY字符画.zip python项目——DIY字符画.zip python项目——DIY字符画.zip ...

    Python源码剖析——深度探索动态语言核心技术

    资源名称:Python源码剖析——深度探索动态语言核心技术资源截图: 资源太大,传百度网盘了,链接在附件中,有需要的同学自取。

    python项目——企业编码管理.zip

    python项目——企业编码管理.zip python项目——企业编码管理.zip python项目——企业编码管理.zip python项目——企业编码管理.zip python项目——企业编码管理.zip python项目——企业编码管理.zip python项目——...

    Python学习笔记(干货) 中文PDF完整版.pdf

    《Python学习笔记(干货) 中文PDF完整版.pdf》是一份全面且深入的Python学习资源,旨在帮助初学者和有经验的程序员进一步提升Python技能。这份资料覆盖了Python的多个核心概念,包括环境搭建、基本语法、数据类型、...

    python项目——看图猜成语.zip

    python项目——看图猜成语.zip python项目——看图猜成语.zip python项目——看图猜成语.zip python项目——看图猜成语.zip python项目——看图猜成语.zip python项目——看图猜成语.zip python项目——看图猜成语....

    python项目——微信机器人.zip

    python项目——微信机器人.zip python项目——微信机器人.zip python项目——微信机器人.zip python项目——微信机器人.zip python项目——微信机器人.zip python项目——微信机器人.zip python项目——微信机器人....

    python项目——甜橙音乐网.zip

    python项目——甜橙音乐网.zip python项目——甜橙音乐网.zip python项目——甜橙音乐网.zip python项目——甜橙音乐网.zip python项目——甜橙音乐网.zip python项目——甜橙音乐网.zip python项目——甜橙音乐网....

    python项目——火车票分析助手.zip

    python项目——火车票分析助手.zip python项目——火车票分析助手.zip python项目——火车票分析助手.zip python项目——火车票分析助手.zip python项目——火车票分析助手.zip python项目——火车票分析助手.zip ...

    python项目——Excel数据分析师.zip

    python项目——Excel数据分析师.zip python项目——Excel数据分析师.zip python项目——Excel数据分析师.zip python项目——Excel数据分析师.zip python项目——Excel数据分析师.zip python项目——Excel数据分析师....

    Python学习笔记.pdf

    **标题与描述解析:** "Python学习笔记.pdf" 的标题直接指出了文档的主题——Python的学习资料,而描述的重复表明该文档的主要内容即为Python的学习笔记。标签 "Python" 进一步强调了主题。 **知识点:** 1. **...

Global site tag (gtag.js) - Google Analytics