`

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学习笔记——socket通信相关资源文件

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

    python小游戏——扫雷

    python小游戏——扫雷

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

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

    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项目...

    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项目——BBS问答社区.zip

    python项目——BBS问答社区.zip python项目——BBS问答社区.zip python项目——BBS问答社区.zip python项目——BBS问答社区.zip python项目——BBS问答社区.zip python项目——BBS问答社区.zip python项目——BBS...

    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项目——玛丽冒险.zip python项目...

    python项目——超级画板.zip

    python项目——超级画板.zip python项目——超级画板.zip python项目——超级画板.zip python项目——超级画板.zip python项目——超级画板.zip python项目——超级画板.zip python项目——超级画板.zip python项目...

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

    这份"Python学习笔记"涵盖了从环境搭建到基础语法,再到数据类型和控制结构等关键知识点,旨在为初学者提供全面的学习指导。 首先,1.1章节介绍了Python的基础,包括Python的起源和历史。Python是由Guido van ...

    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. **...

    083964-夏敏捷-Python课程设计——代码(全部).zip

    本资源“夏敏捷Python课程设计——代码(全部).zip”提供了丰富的Python编程实践项目,涵盖了多个主题,旨在帮助学习者深入理解和掌握Python的核心概念及高级特性。 1. **Tkinter图形界面应用**: - Tkinter是...

    python项目——学生管理系统.zip

    python项目——学生管理系统.zip python项目——学生管理系统.zip python项目——学生管理系统.zip python项目——学生管理系统.zip python项目——学生管理系统.zip python项目——学生管理系统.zip python项目——...

Global site tag (gtag.js) - Google Analytics