【问题标题】:method objects vs function objects , Python class instances vs class方法对象 vs 函数对象,Python 类实例 vs 类
【发布时间】:2016-04-11 17:11:47
【问题描述】:

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

实例对象的有效方法名称取决于其类。经过 定义,作为函数对象的类的所有属性定义 其实例的相应方法。所以在我们的例子中,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。类型没有区别,但教程另有说明。有人可以澄清一下吗?

【问题讨论】:

    标签: python class methods instance


    【解决方案1】:

    Bound vs Unbound 方法 - 一个解释。

    ...或者为什么 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 自己的口中完整阅读his 'History of Python' series

    【讨论】:

      【解决方案2】:

      教程确实错了; 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>>
      

      【讨论】:

      • 很好的答案,我从中学到了一些有趣的东西。
      • 教程没有错。差异在9.3.4 Method objects 部分的最后一段中进行了解释。
      • @hacks:但是,这并不能使这一行的陈述正确。
      • 也就是说你认为函数对象方法对象没有区别?
      • @hacks:不,有很大的不同。
      猜你喜欢
      • 2013-07-05
      • 1970-01-01
      • 2017-01-28
      • 2018-10-25
      • 1970-01-01
      • 2016-01-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多