方法和function的区别

我在做Code Academy的Python教程,对于方法和函数的定义我有点困惑。 从教程:

你已经知道了一些我们用来创buildstring的函数,比如.upper() .lower()str()len()

来自C ++,我会认为.upper().lower()将被称为方法和len()str()函数。 在教程中,这些术语似乎可以互换使用。

Python是否以C ++的方式区分方法和函数?

与方法和函数之间的区别不同 ,我在问Python的细节。 “方法”和“function”这两个术语似乎并不总是遵循链接问题的接受答案中给出的定义。

函数是Python中的可调用对象,即可以使用调用操作符调用 (尽pipe其他对象可以通过实现__call__来模拟函数)。 例如:

 >>> def a(): pass >>> a <function a at 0x107063aa0> >>> type(a) <type 'function'> 

一个方法是一个特殊的function类,可以是绑定的 ,也可以是非绑定的

 >>> class A: ... def a(self): pass >>> Aa <unbound method Aa> >>> type(Aa) <type 'instancemethod'> >>> A().a <bound method Aa of <__main__.A instance at 0x107070d88>> >>> type(A().a) <type 'instancemethod'> 

当然,一个无法绑定的方法是不能被调用的(至less不能直接把实例作为parameter passing):

 >>> Aa() Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: unbound method a() must be called with A instance as first argument (got nothing instead) 

在Python中,在大多数情况下,您将不会注意到绑定方法,函数或可调用对象(即实现__call__的对象)或类构造函数之间的区别。 他们都看起来一样,他们只是有不同的命名约定。 在引擎盖下,这些物体可能看起来有很大的不同。

这意味着一个绑定的方法可以作为一个函数使用,这是使Python如此强大的许多小事情之一

 >>> b = A().a >>> b() 

这也意味着即使len(...)str(...) (后者是一个types构造函数)之间存在根本的区别,在深入挖掘之前,您将不会注意到这个区别:

 >>> len <built-in function len> >>> str <type 'str'> 

如果你仍然不明白方法是如何工作的,那么查看实现可能会澄清一些事情。 当引用不是数据属性的实例属性时,将search其类。 如果名称表示一个有效的类属性是一个函数对象,则方法对象是通过打包实例对象和在一个抽象对象中一起find的函数对象(指针)来创build的:这是方法对象。 当使用参数列表调用方法对象时,会从实例对象和参数列表构造一个新的参数列表,并使用此新参数列表调用函数对象。

http://docs.python.org/2/tutorial/classes.html#method-objects

仔细阅读这个摘录。

它的意思是 :

1 /

一个实例并不真正拥有一个对象作为其属性的方法。
实际上,实例的__dict__中没有“方法”属性( __dict__是对象的名称空间)

2 /

事实上,一个实例在调用“method”属性时似乎有一个“方法”,这是由于一个进程,而不是一个实例名称空间内的方法对象的存在

3 /

此外,在类的名称空间中并不存在方法对象。

但是与实例有所不同,因为在这样的调用完成之后,必定有某个地方会导致一个真正的方法对象,而不是?

一个类的“方法”属性,为了便于使用,实际上是一个函数对象,它是类的名字空间中的属性。
也就是说,一对(函数,函数的标识符)是一个类的__dict__的成员,并且该属性允许解释器在执行方法调用时构造方法对象。

4 /

同样,一个类似乎在调用“method”属性时有一个“方法”的事实,是由于一个进程,而不是一个类的名字空间内的方法对象的存在

编辑我对此不再确定; 最后看

5 /

一个方法对象(不是“方法”对象;我的意思是真正的对象是一个方法,在摘录中描述的内容)是在调用时创build的,它以前不存在。
它是一种包装:它包装指向实例对象和方法所基于的函数对象的指针。

所以,一个方法是基于一个函数的。 这个函数对于我来说是拥有这个“方法”的类的真正属性,因为这个函数真的属于这个类的名字空间( __dict__ ):这个函数被描述为一个<function ......>打印__dict__
这个函数可以通过方法对象使用别名im_func__func__ (参见下面的代码)

我相信这些概念是不是很普遍的知道和理解。 但是下面的代码certificate了我所说的。

 class A(object): def __init__(self,b=0): self.b = b print 'The __init__ object :\n',__init__ def addu(self): self.b = self.b + 10 print '\nThe addu object :\n',addu print '\nThe A.__dict__ items :\n', print '\n'.join(' {0:{align}11} : {1}'.format(*it,align='^') for it in A.__dict__.items()) a1 = A(101) a2 = A(2002) print '\nThe a1.__dict__ items:' print '\n'.join(' {0:{align}11} : {1}'.format(*it,align='^') for it in a1.__dict__.items()) print '\nThe a2.__dict__ items:' print '\n'.join(' {0:{align}11} : {1}'.format(*it,align='^') for it in a2.__dict__.items()) print '\nA.addu.__func__ :',A.addu.__func__ print id(A.addu.__func__),'==',hex(id(A.addu.__func__)) print print 'A.addu :\n ', print A.addu,'\n ',id(A.addu),'==',hex(id(A.addu)) print 'a1.addu :\n ', print a1.addu,'\n ',id(a1.addu),'==',hex(id(a1.addu)) print 'a2.addu :\n ', print a2.addu,'\n ',id(a2.addu),'==',hex(id(a2.addu)) a2.addu() print '\na2.b ==',a2.b print '\nThe A.__dict__ items :\n', print '\n'.join(' {0:{align}11} : {1}'.format(*it,align='^') for it in A.__dict__.items()) 

结果

 The __init__ object : <function __init__ at 0x011E54B0> The addu object : <function addu at 0x011E54F0> The A.__dict__ items : __module__ : __main__ addu : <function addu at 0x011E54F0> __dict__ : <attribute '__dict__' of 'A' objects> __weakref__ : <attribute '__weakref__' of 'A' objects> __doc__ : None __init__ : <function __init__ at 0x011E54B0> The a1.__dict__ items: b : 101 The a2.__dict__ items: b : 2002 A.addu.__func__ : <function addu at 0x011E54F0> 18765040 == 0x11e54f0 A.addu : <unbound method A.addu> 18668040 == 0x11cda08 a1.addu : <bound method A.addu of <__main__.A object at 0x00CAA850>> 18668040 == 0x11cda08 a2.addu : <bound method A.addu of <__main__.A object at 0x011E2B90>> 18668040 == 0x11cda08 a2.b == 2012 The A.__dict__ items : __module__ : __main__ addu : <function addu at 0x011E54F0> __dict__ : <attribute '__dict__' of 'A' objects> __weakref__ : <attribute '__weakref__' of 'A' objects> __doc__ : None __init__ : <function __init__ at 0x011E54B0> 

编辑

有什么困扰我,我不知道这个问题的深层内涵:

上面的代码显示A.addua1.addua2.addu都是相同的方法对象,具有唯一的标识。
然而A.addu被说成是一种无约束的方法,因为它没有关于特定实例的任何信息,
a1.addua2.addu则被称为绑定方法,因为每个方法都有指定方法操作必须关注的实例的信息。
从逻辑上来说,对我来说,这意味着这三种情况下的方法应该是不同的。

但是三者的身份是相同的,而且这个身份与方法所基于的function的身份是不同的。
由此得出这样一个结论,即这个方法确实是一个生活在记忆中的客体,它不会从一个实例调用到另一个实例的另一个调用。

然而 ,即使在创build实例和调用“方法” addu()之后,打印该类的名称空间__dict__ ,该名称空间不会公开一个新的对象,该对象可以被标识为与addu函数不同的方法对象。

这是什么意思 ?
它给我的印象是,只要一个方法对象被创build,它就不会被销毁,而是存在于内存(RAM)中。
但是它隐藏起来,只有形成干涉者function的过程知道如何以及在哪里find它。
这个隐藏的对象,真正的方法对象,必须能够改变引用到函数必须被应用到的实例,或者如果被称为未绑定的方法,则引用None 。 这就是我所认为的,但这只是脑力激荡的假设。

有人知道这个讯问吗?


为了回答这个问题,可以认为调用上.lower 函数是正确的,因为实际上,它们是以每个类的每个方法为基础的函数。

但是,下面的结果是特殊的,可能是因为它们是内置的方法/函数,而不是我的代码中的用户方法/函数。

 x = 'hello' print x.upper.__func__ 

结果

  print x.upper.__func__ AttributeError: 'builtin_function_or_method' object has no attribute '__func__' 

在下面的类定义中:

 class MyClass: """A simple example class""" def f(self): return 'hello world' 
  • MyClass
  • functionf()
  • 方法无(其实不适用)

让我们创build一个上面的类的实例。 我们将通过将class object, ie MyClass()分配给var x

  x = MyClass() 

这里,

  • function
  • 方法xf()

当我们将x赋给MyClass()时,不要忘记function object MyClass.f被用来定义(内部) method object xf

基本上,是的,Python确实区分了它们,但是在Python中,将方法视为函数的一个子集是很常见的。 方法与类或实例关联,而“独立函数”则不是。 某个方法也是一个函数,但是可能有函数不是方法。

正如乔恩·克莱门特(Jon Clements)在评论中提到的那样,这个区别并不像在C ++中那么铁定。 独立函数可以在运行时“转换”为方法,并且可以将方法分配给variables,使得它们的有效行为与独立函数不同。 所以方法和function之间的界限是可渗透的。