`
huangyiiiiii
  • 浏览: 118755 次
  • 性别: Icon_minigender_1
最近访客 更多访客>>
社区版块
存档分类
最新评论

理解 python 的 method 和 function 兼谈 descriptor

阅读更多
总是看到有人对 python 中的 methodfunction 之间关系的困惑,其实初学 python 时我也困惑过,不过现在自认为对这个问题还是基本清楚了 ;-)。

我在前面写过的 selfless python 里面说过 method 本质上就是 function,这个从它们的形式上也看得出来,呵呵,而让人困惑的问题主要就是那个隐式传入的 self 参数。这其实是利用了descriptor 机制,请看代码:

>>> class Temp(object):
... def test(self, a):
... print self, a
...
>>> func = Temp.__dict__['test']
>>> func
<function at="" test="">
>>> func(1, 2)
1 2
</function>
由此可见 test 就是个不折不扣的函数!
>>> Temp.test
<unbound temp.test="" method="">
>>> t = Temp()
>>> t.test
<bound of="" temp.test="" method=""><__main__.Temp object at 0x00B46CD0>>
</bound></unbound>
但是这又是怎么回事了?哪里冒出个 bound/unbound method 来了?
>>> dir(func)
['__call__', '__class__', '__delattr__', '__dict__', '__doc__', '__get__', '__ge
tattribute__', '__hash__', '__init__', '__module__', '__name__', '__new__', '__r
educe__', '__reduce_ex__', '__repr__', '__setattr__', '__str__', 'func_closure',
'func_code', 'func_defaults', 'func_dict', 'func_doc', 'func_globals', 'func_na
me']
请注意其中的 __get__ 方法,这就是 descriptor 的标志(任何定义了 __get__, __set__, __delete__ 三个方法中的一个或几个的对象都是 descriptor ,这几个方法的意思大家应该能猜到了)

根据对象 attribute 的查找策略,当 t.test 时,首先根据 attribute查找策略找到这个函数对象,然后会发现它有 __get__ 属性,则调用之,并把它的返回值当作该 attribute 的值。
Temp.test 等价于 Temp.__dict__['test'].__get__(None, Temp)
t.test 等价于 Temp.__dict__['test'].__get__(t, Temp)

其实你可以把 func.__get__ 的实现想象成下面这个等价物:

>>> class Function(object):
... def __get__(self, obj, objtype=None):
... import types
... return types.MethodType(self, obj, objtype)

到这里事情已经比较清楚了,不过还有一点可能仍然会让你感到困惑:

>>> Temp.test = test

>>> t.test(1)
<__main__.Temp object at 0x00B46E90> 1
>>> t.test = test
>>> t.test(1)
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: test() takes exactly 2 arguments (1 given)
>>> t.test
<function at="" test="">
</function></stdin>

咦?不是说 functiondescriptor 的吗?怎么这里没有去调用它的 __get__ 方法呢?

另外:

>>> class Meta(type):pass
...
>>> class Temp(object):
... __metaclass__ = Meta
...
>>> class Desc(object):
... def __get__(self, instance, type):
... print instance, type
...
>>> desc = Desc()
>>> Meta.d = desc
>>> Meta.d
None <class __main__.meta="">

>>> Temp.d
<class __main__.temp=""> <class __main__.meta="">
>>> Temp.d = desc
>>> Temp.d
None <class __main__.temp="">
>>> t = Temp()
>>> t.d
<__main__.Temp object at 0x00B46DD0> <class __main__.temp="">

>>> t.d = desc
>>> t.d
<__main__.Desc object at 0x00B46D30>
</class></class></class></class></class>

注意到,到最后一步 t.d 的时候也没有对 descriptor 求值。这个道理和上面那个是一样的,仔细看一下 attribute 查找策略 就可以找到答案了, descriptor 只有绑定在 type object 上才有效。

这里我们涉及到了 python对象一种分类: type object type object ,这两种对象在 attribute 查找过程中的待遇是不一样的。

简单地说 type object 包括 type, type 的子类( 也就是 metaclass 了 )、 type 的实例( 也就是 class 了 )

一般来说 type object type object 不光在 attribute 受到不平等待遇,而且非 type object 还不能成为其它对象的基类型,想成为 metaclass 更是痴心妄想了。

不过就像我以前说过的那样,python 中的对象本质上都是平等的,区分它们的唯一方法是它们的接口,所以我相信所谓 type object type object 的区别也只在于接口而已。也就是说只要实现 type object 所需的接口,任何对象都可以成为 type object

参考:

How-To Guide for Descriptors

Python Attributes and Methods

分享到:
评论

相关推荐

    Python中的Descriptor描述符学习教程

    下面先介绍一下Python中成员变量的定义和使用。 我们知道,在Python中定义类成员和C/C++相比得到的结果具有很大的差别。如下面的定义: class Cclass { int I; void func(); }; Cclass c; 在上面的定义中,...

    轻松理解Python 中的 descriptor

    Python中的descriptor是一个重要的概念,它是Python面向对象...理解descriptor的工作原理对于深入理解Python的面向对象编程至关重要。通过掌握descriptor,开发者可以创建更灵活、更可控的类结构,以满足复杂的需求。

    python学习-20-descriptor

    简单易学:Python的语法简洁明了,易于理解和学习。 高级特性:Python支持面向对象编程、函数式编程等高级特性,使得代码更加模块化和可重用。 广泛的库和框架:Python拥有丰富的第三方库和框架,可以快速开发各种...

    Python库 | person_descriptor-0.1.0.tar.gz

    资源分类:Python库 所属语言:Python 资源全名:person_descriptor-0.1.0.tar.gz 资源来源:官方 安装方法:https://lanzao.blog.csdn.net/article/details/101784059

    Python & Matlab code for local feature descriptor evaluation wit

    标题中的“Python & Matlab code for local feature descriptor evaluation with the HPatches dataset”表明这是一个关于使用Python和Matlab评估局部特征描述符的代码库,且与HPatches数据集配合使用。HPatches数据...

    Python描述符descriptor使用原理解析

    Python中的描述符(descriptor)是理解面向对象编程中属性访问机制的关键概念。描述符是实现了特定特殊方法(如`__get__`、`__set__`和`__del__`)的类,这些方法控制了对象属性的获取、设置和删除操作。描述符在...

    Python描述器descriptor详解

    这说明了函数和方法之间的关系,并且解释了函数对象和方法对象在类型上是有所区别的:函数类型是&lt;type 'function'&gt;,而普通实例方法的类型是&lt;type 'instance method'&gt;。 在描述器的机制中,当通过类访问一个属性时...

    Python 的描述符 descriptor详解

    Python 在 2.2 版本中引入了descriptor(描述符)功能,也正是基于这个功能实现了新式类(new-styel class)的对象模型,同时解决了之前版本中经典类 (classic class) 系统中出现的多重继承中的 MRO(Method Resolution...

    cron-descriptor:一个将cron表达式转换为人类可读字符串的Python库

    一个将cron表达式转换为人类可读字符串的Python库。 从移植到Python。 作者:亚当·舒伯特(Adam Schubert)( ) 原始作者和信誉:Brady Holt( ) 执照: 特征 支持所有cron表达式特殊字符,包括* /,-? LW,#...

    解密Python中的描述符(descriptor)

    Python中包含了许多内建的语言特性,它们使得代码简洁且易于理解。这些特性包括列表/集合/字典推导式,属性(property)、以及装饰器(decorator)。对于大部分特性来说,这些“中级”的语言特性有着完善的文档,...

    Python3高级教程_python3_高级教程_电子版_

    元编程是编写操作代码的代码,Python3提供了丰富的元类(metaclass)和描述符(descriptor)机制。元类可以自定义类的行为,如动态创建属性或方法;描述符则是实现了特定接口的对象,能控制属性的访问和赋值行为。 ...

    实现protobuf和json互相转换python3源码

    在IT行业中,数据序列化和反序列化是一个关键任务,特别是在网络通信、数据存储和跨平台数据交换中。Google推出的Protocol Buffers...通过理解和应用这些技术,你可以优化你的应用程序,提高数据传输的效率和兼容性。

    Python源码解析

    10. **元编程**:Python的动态性体现在元类(metaclass)、描述符(descriptor)、属性(property)等方面,源码分析可以帮助理解这些高级特性的实现。 通过阅读Python2.7的源码,开发者不仅可以深化对Python语言的...

    ZigBee问答之“profile”、“descriptor”

    - **协同工作**: Profile定义了一组设备应该具备什么样的功能和服务,而Descriptor则详细描述了每台设备如何实现这些功能和服务。通过这种方式,不同设备能够理解彼此并实现有效的交互。 #### 四、Profile与其它...

    Python3.7.3官方中文文档

    这份官方中文文档为学习和理解Python 3.7.3提供了全面的指南。 **参考文档(reference.pdf)** 参考文档详尽地列出了Python 3.7.3的所有内置函数、模块、类和接口。它包含了语言规范和标准库的详细信息,帮助...

Global site tag (gtag.js) - Google Analytics