方法和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.addu
, a1.addu
和a2.addu
都是相同的方法对象,具有唯一的标识。
然而A.addu
被说成是一种无约束的方法,因为它没有关于特定实例的任何信息,
而a1.addu
和a2.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
- function : f()
- 方法 : 无(其实不适用)
让我们创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之间的界限是可渗透的。