python 描述器 详解_Python描述器descriptor详解
前面说了descriptor,这个东西其实和Java的setter,getter有点像。但这个descriptor和上文中我们开始提到的函数方法这些东西有什么关系呢?
所有的函数都可以是descriptor,因为它有__get__方法。
>>> def hello():
pass
>>> 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']
>>>
注意,函数对象没有__set__和__del__方法,所以它是个non-data descriptor.
方法其实也是函数,如下:
>>> class T(object):
def hello(self):
pass
>>> T.__dict__['hello']
>>>
或者,我们可以把方法看成特殊的函数,只是它们存在于类 中,获取函数属性时,返回的不是函数本身(比如上面的),而是返回函数的__get__方法的返回值,接着上面类T的定义:
>>> T.hello 获取T的hello属性,根据查找策略,从T的__dict__中找到了,找到的是,但不会直接返回,因为它有__get__方法,所以返回的是调用它的__get__(None, T)的结果:一个unbound方法。
>>> f = T.__dict__['hello'] #直接从T的__dict__中获取hello,不会执行查找策略,直接返回了
>>> f
>>> t = T()
>>> t.hello #从实例获取属性,返回的是调用的__get__(t, T)的结果:一个bound方法。
>
>>>
为了证实我们上面的说法,在继续下面的代码(f还是上面的):
>>> f.__get__(None, T)
>>> f.__get__(t, T)
>
好极了!
总结一下:
1.所有的函数都有__get__方法
2.当函数位于类的__dict__中时,这个函数可以认为是个方法,通过类或实例获取该函数时,返回的不是函数本身,而是它的__get__方法返回值。
我承认我可能误导你认为方法就是函数,是特殊的函数。其实方法和函数还是有区别的,准确的说:方法就是方法,函数就是函数。
>>> type(f)
>>> type(t.hello)
>>> type(T.hello)
>>>
函数是function类型的,method是instancemethod(这是普通的实例方法,后面会提到classmethod和staticmethod)。
关于unbound method和bound method,再多说两句。在c实现中,它们是同一个对象(它们都是instancemethod类型的),我们先看看它们里面到底是什么
>>> dir(t.hello)
['__call__', '__class__', '__cmp__', '__delattr__', '__doc__', '__get__', '__getattribute__',
'__hash__', '__init__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__',
'__str__', 'im_class', 'im_func', 'im_self']
__call__说明它们是个可调用对象,而且我们还可以猜测,这个__call__的实现应该大致是:转调另外一个函数(我们期望的哪个,比如上面的hello),并以对象作为第一参数。
要 注意的是im_class,im_func,im_self。这几个东西我们并不陌生,在t.hello里,它们分别代表T,hello(这里是存储在 T.__dict__里的函数hello)和t。有了这些我们可以大致想象如何纯Python实现一个instancemethod了:)。
其实还有几个内建函数都和descriptor有关,下面简单说说。
classmethod
classmethod能将一个函数转换成类方法,类方法的第一个隐含参数是类本身 (普通方法的第一个隐含参数是实例本身),类方法即可从类调用,也可以从实例调用(普通方法只能从实例调用)。
>>> class T(object):
def hello(cls):
print 'hello', cls
hello = classmethod(hello) #两个作用:把hello装换成类方法,同时隐藏作为普通方法的hello
>>> t = T()
>>> t.hello()
hello
>>> T.hello()
hello
>>>
注意:classmethod是个类,不是函数。classmethod类有__get__方法,所以,上面的t.hello和T.hello获得实际上是classmethod的__get__方法返回值
>>> t.hello
>
>>> type(t.hello)
>>> T.hello
>
>>> type(T.hello)
>>>
从 上面可以看出,t.hello和T.hello是instancemethod类型的,而且是绑定在T上的。也就是说classmethod的 __get__方法返回了一个instancemethod对象。从前面对instancemethod的分析上,我们应该可以推断:t.hello的 im_self是T,im_class是type(T是type的实例),im_func是函数hello
>>> t.hello.im_self
>>> t.hello.im_class
>>> t.hello.im_func
>>>
完全一致!所以实现一个纯Python的classmethod也不难:)
staticmethod
staticmethod能将一个函数转换成静态方法,静态方法没有隐含的第一个参数。
class T(object):
def hello():
print 'hello'
hello = staticmethod(hello)
>>> T.hello() #没有隐含的第一个参数
hello
>>> T.hello
>>>
T.hello直接返回了一个函数。猜想staticmethod类的__get__方法应该是直接返回了对象本身。
还有一个property,和上面两个差不多,它是个data descriptor。
python 描述器 详解_Python描述器descriptor详解相关推荐
- python中装饰器的作用_Python装饰器详解,详细介绍它的应用场景
装饰器的应用场景附加功能 数据的清理或添加:函数参数类型验证 @require_ints 类似请求前拦截数据格式转换 将函数返回字典改为 JSON/YAML 类似响应后篡改为函数提供额外的数据 moc ...
- python描述器 触发事件_Python描述器引导(转)
原文:http://pyzh.readthedocs.io/en/latest/Descriptor-HOW-TO-Guide.html 作者: Raymond Hettinger 联系: 翻译: h ...
- python自带装饰器详解_Python装饰器详解
引言 装饰器简单来说是我们向一个现有的已经存在的函数或对象添加新的功能,同时呢我们又不用改变他现有的结构. 为什么我们需要装饰器 我们假设你的程序实现了say_hello()和say_goodbye( ...
- python解析器的作用_Python 解析器
2008-01-07 17:55 星期一 嵌入Python解析器执行一些简单的Python 脚本脚本很容易,但是当python解析器用到扩展模块时和多个线程都需要Python解析器执行脚本时,遇到了一 ...
- python中的装饰器怎么运行_Python 装饰器入门(上)
翻译前想说的话: 这是一篇介绍python装饰器的文章,对比之前看到的类似介绍装饰器的文章,个人认为无人可出其右,文章由浅到深,由函数介绍到装饰器的高级应用,每个介绍必有例子说明.文章太长,看完原文后 ...
- python装饰器与闭包_Python 装饰器和闭包
Python 装饰器和闭包 装饰器是 Python 中常见的语法糖,这篇文章讲了闭包和装饰器的原理,并且分析了函数中变量的作用域,以及尝试总结了常见的坑. 装饰器基础 首先来看看装饰器的定义:装饰器本 ...
- python装饰器参数讲解_python装饰器的详细解析
写在前面: python装饰器(fuctional decorators)就是用于拓展原来函数功能的一种函数,目的是在不改变原函数名(或类名)的情况下,给函数增加新的功能. 这个函数的特殊之处在于它的 ...
- python中的eof错误_python – 解析器YACC中的EOF错误
我试图使用PLY库中为Python提供的yacc解析器来解析字符串. 解析器本身很长,但我遇到的问题是它总是给我同样的错误,无论我放什么样的字符串. 错误是这样的: yacc:输入中的解析错误. EO ...
- python装饰器应用论文_Python装饰器的应用场景代码总结
装饰器的应用场景 附加功能 数据的清理或添加: 函数参数类型验证 @require_ints 类似请求前拦截 数据格式转换 将函数返回字典改为 json/YAML 类似响应后篡改 为函数提供额外的数据 ...
- python装饰器传递参数_Python装饰器高级版—Python类内定义装饰器并传递self参数...
本文重点:解决了类里面定义的装饰器,在同一个类里面使用的问题,并实现了装饰器的类属性参数传递 目录: 一.基本装饰器 二.在类里定义装饰器,装饰本类内函数 三.类装饰器 正文: 一.基本装饰器 装饰不 ...
最新文章
- Zepto源码分析-event模块
- gitlab的搭建与汉化
- Cookie和Session-学习笔记02【Cookie案例、JSP改造Cookie案例】
- python 拓扑排序 dfs bfs_bfs与dfs的优缺点?
- bootstrap 利用jquery 添加disabled属性
- 登录工程:传统 Web 应用中的身份验证技术
- 专业本的C语言,以解决本专业问题为导向的C语言程序设计课程教学探索
- LeetCode 第 197 场周赛(468/5273,前8.88%)
- kafka java_Java操作Kafka
- java jar 启动项目,SpringBoot项目运行jar包启动的步骤流程解析
- mysql 5.7 多条件 in_5分钟了解MySQL5.7对in用法有什么黑科技
- 「leetcode」C++题解:四数之和 / 4Sum 三数之和的延伸,建议使用双指针法
- arcgis视频教程 定制技术服务_坐标转换_等高线生成各种问题远程解决
- jQuery each()跳出循环
- Eclipse TPTP 分析程序性能
- 心肝火旺是夏季宝宝晚上睡不踏实的主要原因
- java五子棋棋盘_java绘制五子棋棋盘代码示例
- 以太网帧,IP,TCP,UDP首部结构
- lftp的使用以及常见的指令
- 阿里开发手册-MySQL规约
热门文章
- redis-rdb-tools来解析分析reids dump文件及内存使用量
- 生产服务器环境最小化安装后Centos 6.5优化配置备忘
- mount: unknown filesystem type 'smbfs' 问题解决
- forget password of WEBLOGIC user
- 《深入理解Nginx》阅读与实践(四):简单的HTTP过滤模块
- eclipse rcp应用程序重启
- 快速消费品行业的营销费用的管理(2)----营销费用的分类
- MapInfo开发心得——多地图关联篇【转】
- Silverlight3实现按路径运动[原创]
- 菜鸟学SQL注入 --- 一个简单的教学案例