方法对象与函数对象,Python类实例与类

时间:2013-01-12 22:57:08

标签: python class methods instance

我正在尝试验证实例属性和类属性之间的区别,如2012年11月1日,第9章:类,最后一行(source)的Python教程2.7.3版所示:

  

实例对象的有效方法名称取决于其类。通过   定义,作为函数对象的类的所有属性定义   其实例的相应方法。所以在我们的例子中,x.f是一个   有效的方法引用,因为MyClass.f是一个函数,但x.i不是,   因为MyClass.i不是。 但是x.f与MyClass.f不是一回事 -   它是方法对象,而不是函数对象。

我有这个:

class MyClass:    
   """A simple example class"""    
   i = 12345   
   def f():    
      return 'hello world'

然后我这样做:

>>> x = MyClass()
>>> x.f
<bound method MyClass.f of <__main__.MyClass instance at 0x02BB8968>>
>>> MyClass.f
<unbound method MyClass.f>
>>> type(MyClass.f)
<type 'instancemethod'>
>>> type(x.f)
<type 'instancemethod'>

请注意,x.fMyClass.f的类型都是instancemethod。类型没有区别,但教程另有说法。请有人澄清一下吗?

2 个答案:

答案 0 :(得分:23)

绑定 vs 未绑定方法 - 解释。

...或者为什么Python有你指出的行为。

首先,请注意这在3.x中有所不同。在3.x中,您将MyClass.f作为函数,x.f作为方法 - 正如预期的那样。这种行为本质上是一个糟糕的设计决策,后来被改变了。

这样做的原因是Python有一个与大多数语言不同的方法的概念,它本质上是一个函数,第一个参数预先填充为实例(self)。此预填充使绑定方法

>>> x.foo
<bound method MyClass.foo of <__main__.MyClass instance at 0x1004989e0>>

在Python 2.x及之前,有人认为未附加到实例的方法将是未绑定方法,这是一个限制第一个参数的函数({{1 }}),必须是对象的实例。然后就可以将其绑定到实例并成为绑定方法

self

随着时间的推移,很明显一个未绑定的方法实际上只是一个具有这个奇怪限制的函数并不重要(>>> MyClass.foo <unbound method MyClass.foo> 必须是'正确的'类型) ,所以他们被从语言中删除(在3.x中)。这基本上是打字self,适合该语言。

self

进一步阅读。

这是一个(浓缩的,记忆中的)解释,可以从Python创建者Guido van Rossum在his 'History of Python' series自己的口中全部阅读。

答案 1 :(得分:13)

教程确实是错误的; class.functionnameinstance.functionname都返回一个方法对象。

接下来发生的是函数是descriptor并且调用了它们的__get__方法,返回一个方法。方法的__func__属性指向原始函数:

>>> class Foo(object):
...     def bar(self):
...         pass
... 
>>> Foo.bar
<unbound method Foo.bar>
>>> Foo().bar
<bound method Foo.bar of <__main__.Foo object at 0x1090d6f10>>
>>> # accessing the original function
...
>>> Foo.bar.__func__
<function bar at 0x1090cc488>
>>> # turning a function back into a method
...
>>> Foo.bar.__func__.__get__(None, Foo)
<unbound method Foo.bar>
>>> Foo.bar.__func__.__get__(Foo(), Foo)
<bound method Foo.bar of <__main__.Foo object at 0x1090d6f90>>

但是这在Python 3中已经发生了变化; Foo.bar返回函数本身,未绑定的方法不再存在:

$ python3.3
Python 3.3.0 (default, Sep 29 2012, 08:16:08) 
[GCC 4.2.1 Compatible Apple Clang 3.1 (tags/Apple/clang-318.0.58)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> class Foo:
...     def bar(self):
...         pass
... 
>>> Foo.bar
<function Foo.bar at 0x105512dd0>
>>> Foo.bar.__get__(None, Foo)
<function Foo.bar at 0x105512dd0>
>>> Foo.bar.__get__(Foo(), Foo)
<bound method Foo.bar of <__main__.Foo object at 0x10552fe10>>