实例方法还是功能?

时间:2013-12-19 14:15:53

标签: python python-2.7

今天我定义了一个专门用于测试下一步的课程:

class B(object):
    def p(self):
        print("p")

后来我这样做了:

>>> type(B.__dict__['p'])
<type 'function'>
>>> type(B.p)
<type 'instancemethod'>

那么,为什么? B.pB.__dict__['p']不是同一个对象吗?

当我尝试这个时,我的惊讶就增加了:

>>> B.__dict__['p']
<function p at 0x3d2bc80>
>>> type(B.__dict__['p'])
<type 'function'>

好的,到目前为止一直很好,类型是两个结果function,但是当我尝试时:

>>> B.p
<unbound method B.p>
>>> type(B.p)
<type 'instancemethod'>

什么?!,为什么? unbound methodinstancemethod?那些是一样的吗?为什么有两个不同的名字?

好吧,看来python充满惊喜!

这就是我正在使用的python:

Python 2.7.4 (default, Sep 26 2013, 03:20:26) 
[GCC 4.7.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.

3 个答案:

答案 0 :(得分:23)

这是一个非常好的问题。

要清除一些事情:

  1. 当通过其类(例如B.p)访问方法名称时,它表示未绑定
  2. 否则通过其类实例(例如B().p)访问该方法时,称其为绑定
  3. 绑定未绑定之间的主要区别在于,如果绑定,第一个参数将隐式地是调用的实例类。这就是我们在定义它时为每个方法添加self作为第一个参数的原因。当 unbound 时,您必须显式传递要应用该方法逻辑的类的实例。

    例如:

    class B(object):
        def foo(self):
            print 'ok'
    
    >>>B().foo()
    ok
    >>>B.foo()
    Exception, missing an argument.
    >>>B.foo(B())
    ok
    

    这是绑定未绑定的基本解释。现在关于__dict__古怪。 Python中的任何对象都可以定义__get____set__方法,当它们是类中的属性时,它控制对它们的访问。这些被称为描述符

    简单来说,当您通过其实例或类访问类的属性(属性)时,Python不会直接返回该对象,而是调用__get____set__方法反过来返回一个方便的对象来使用。

    Python中的函数会覆盖此__get__方法。因此,当您发出B.fooB().foo时,它会返回instancemethod类型,这是function类型的包装器(一个包装器,它隐含地传递self作为第一个参数)。当您通过原始类字典访问该函数时,不会调用__get__,因为您没有将它们作为类的属性访问,因此返回值为 raw 功能

    关于这个话题有很多话要说,我试着给这样一个聪明的主题提供一个非常简单的答案。您可以在Guido的博客文章The Inside Story on New-Style Classes上找到权威性信息,非常值得推荐。

    更新:关于您的上一个例子:

    >>> B.p
    <unbound method B.p>
    >>> type(B.p)
    <type 'instancemethod'>
    

    请注意,在Python的解释器中>>>B.p实际上并不打印对象的类型,而是打印对象的__repr__方法。您可以通过执行>>>print B.p.__repr__()并查看其结果相同来检查:)

    Python充满了间接和委托,这就是它如此灵活的原因。

    希望这能澄清一点。

答案 1 :(得分:4)

  

那么,为什么? B.pB.__dict__['p']不是同一个对象吗?

没有。属性访问是神奇的;当按属性名访问用户定义的方法时,会返回绑定方法或未绑定方法(这在Python 3中更改;根本不再有未绑定方法;如果通过访问实例方法,则会获得常规函数class object);通过字典直接访问可以绕过这种魔力。

  

什么?!,为什么? unbound方法和instancemethod?,那些是一样的吗?为什么有两个不同的名字?

用户定义的方法属于instancemethod类型,除非它是使用@classmethod@staticmethod装饰器定义的。它可以是绑定的实例方法(当作为实例的属性访问时)或未绑定的方法(当作为类的属性访问时)。

(有关说明,请参阅http://docs.python.org/2/reference/datamodel.html的“用户定义的方法”部分。)

答案 2 :(得分:2)

  

那么,为什么?不是B.p和B. dict ['p']是同一个对象吗?

显然他们不是。请阅读此文:https://wiki.python.org/moin/FromFunctionToMethod以获得更深入的解释。