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

2024-04-25 05:47:32 发布

您现在位置:Python中文网/ 问答频道 /正文

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

Valid method names of an instance object depend on its class. By definition, all attributes of a class that are function objects define corresponding methods of its instances. So in our example, x.f is a valid method reference, since MyClass.f is a function, but x.i is not, since MyClass.i is not. But x.f is not the same thing as MyClass.f — it is a method object, not a function object.

我有这个:

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。在类型上没有区别,但是教程中说的不是。有人能澄清一下吗?


Tags: ofinstance属性objectistypemyclassnot
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>>

BoundvsUnbound方法-一个解释

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

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

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

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

在Python2.x和之前的版本中,有人认为没有附加到实例的方法应该是一个未绑定的方法,这是一个函数,其限制是第一个参数(self)必须是对象的实例。然后,它就可以绑定到一个实例,并成为一个绑定方法

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

随着时间的推移,很明显,一个未绑定的方法实际上只是一个具有这种奇怪限制的函数,这并不重要(即self必须是'correct'类型),因此它们被从语言中删除(在3.x中)。这基本上就是duck类型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自己的嘴里完整地阅读。

相关问题 更多 >