23

我正在尝试验证 2012 年 11 月 1 日 Python 教程 2.7.3 版第 9 章:类,第 66 页最后一行(来源)中列出的实例属性和类属性之间的区别:

实例对象的有效方法名称取决于其类。根据定义,作为函数对象的类的所有属性都定义了其实例的相应方法。所以在我们的例子中,xf 是一个有效的方法引用,因为 MyClass.f 是一个函数,但 xi 不是,因为 MyClass.i 不是。但是 xf 与 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.finstancemethod MyClass.f。类型没有区别,但教程另有说明。有人可以澄清一下吗?

4

2 回答 2

29

绑定与非绑定方法 - 解释。

...或者为什么 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 及之前的版本中,没有附加到实例的方法被认为是未绑定的方法,这是一个限制第一个参数 ( self) 必须是对象实例的函数。然后就可以将其绑定到实例并成为绑定方法

>>> MyClass.foo
<unbound method MyClass.foo>

随着时间的推移,很明显,未绑定的方法实际上只是一个具有这种奇怪限制的函数,这并不重要(self必须是“正确”类型),因此它们被从语言中删除(在 3.x 中)。这本质上是self适合语言的鸭式打字。

Python 3.3.0 (default, Dec  4 2012, 00:30:24) 
>>> x.foo
<bound method MyClass.foo of <__main__.MyClass object at 0x100858ed0>>
>>> MyClass.foo
<function MyClass.foo at 0x10084f9e0>

进一步阅读。

这是一个(根据记忆浓缩)解释,可以从 Python 创造者 Guido van Rossum 在他的“Python 历史”系列中自己的口中完整阅读。

于 2013-01-12T23:04:06.927 回答
13

教程确实错了;两者都class.functionname返回instance.functionname一个方法对象。

发生的事情是一个函数是一个描述符,并且它们的__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>>
于 2013-01-12T23:01:12.620 回答