方法和功能之间的区别
这个问题在这里已经有了答案:
函数是Python中的可调用对象,即可以使用调用操作符调用(尽管其他对象可以通过实现__call__
来模拟函数)。 例如:
>>> def a(): pass
>>> a
<function a at 0x107063aa0>
>>> type(a)
<type 'function'>
方法是一种特殊的功能类,可以被绑定或不被绑定。
>>> class A:
... def a(self): pass
>>> A.a
<unbound method A.a>
>>> type(A.a)
<type 'instancemethod'>
>>> A().a
<bound method A.a of <__main__.A instance at 0x107070d88>>
>>> type(A().a)
<type 'instancemethod'>
当然,不能调用一个未绑定的方法(至少不需要直接将实例作为参数传递):
>>> A.a()
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(...)
(后者是一个类型构造函数)之间存在根本差异,但在深入挖掘之前,您将不会注意到这种差异:
>>> len
<built-in function len>
>>> str
<type 'str'>
如果您仍然不明白方法是如何工作的,那么查看实现可能会澄清一些问题。 当引用不是数据属性的实例属性时,将搜索其类。 如果名称表示一个有效的类属性,它是一个函数对象,则通过打包(指向)实例对象和在抽象对象中一起找到的函数对象来创建方法对象:这是方法对象。 当使用参数列表调用方法对象时,会从实例对象和参数列表构造一个新参数列表,并使用此新参数列表调用函数对象。
http://docs.python.org/2/tutorial/classes.html#method-objects
仔细阅读本摘录。
它的意思是 :
1 /
一个实例并不真正拥有一个对象作为其属性的方法。
实际上,实例的__dict__
中没有“方法”属性( __dict__
是对象的名称空间)
2 /
事实上,一个实例在调用“method”属性时似乎有一个“方法”,这是由于一个进程,而不是一个实例名称空间内的方法对象的存在
3 /
而且,在类的名称空间中并不存在方法对象。
但是与实例有所不同,因为在这样的调用完成时,必定会有某个地方导致真正的方法对象,但是不能?
为了便于使用,所谓的类的“方法”属性实际上是在类的命名空间中作为属性的函数对象。
也就是说,一对(函数,函数的标识符)是类的__dict__
的成员,并且该属性允许解释器在执行方法调用时构造方法对象。
4 /
同样,一个类在调用“method”属性时似乎有一个“方法”的事实归因于一个过程,而不是类的命名空间内的方法对象的存在
编辑我对此不再确定; 最后看
5 /
方法对象(不是“方法”对象;我的意思是真正的对象实际上是一个方法,在摘录中描述的内容)是在调用时创建的,它以前不存在。
它是一种包装:它包装指向实例对象和方法所基于的函数对象的指针。
所以,一种方法是基于一个函数的。 这个函数对于我来说是拥有上述“方法”的类的真正属性,因为这个函数实际上属于类的名字空间( __dict__
):这个函数被描述为<function ......>
当打印__dict__
。
这个函数可以通过使用别名im_func
或__func__
的方法对象来__func__
(参见下面的代码)
。
我相信这些概念并不是很普遍的知道和理解。 但下面的代码证明了我所说的。
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
被称为绑定方法,因为每个人都有指定必须与该方法的操作有关的实例的信息。
从逻辑上来说,对我而言,这意味着这三种情况下的方法应该不同。
但是三者的身份是相同的,而且这个身份不同于该方法所基于的功能的身份。
这导致了这样一个结论:该方法实际上是一个生活在记忆中的对象,并且它不会从一个实例调用到另一个实例的另一个调用。
但是 ,即使在创建实例并调用“method” addu()
之后,打印该类的名称空间__dict__
,该名称空间不会公开可以识别的方法对象的新对象,而不同于addu
函数。
这是什么意思 ?
它给我的印象是,只要创建了一个方法对象,它就不会被销毁,而是存在于内存(RAM)中。
但它隐藏起来,只有形成实际操作者的过程知道如何以及在哪里找到它。
这个隐藏的对象,即真实的方法对象,必须能够将引用更改为该函数必须应用到的实例,或者如果将其作为未绑定方法调用,则引用None
。 这就是我所认为的,但这只是脑力激荡的假设。
有人知道这个讯问有什么?
为了回答这个问题,可以认为调用.upper
和.lower
函数是正确的,因为实际上它们是基于功能的,而.lower
每个类的方法。
但是,下面的结果是特殊的,可能是因为它们是内建的方法/函数,而不是用户的方法/函数,就像我的代码中那样。
x = 'hello'
print x.upper.__func__
结果
print x.upper.__func__
AttributeError: 'builtin_function_or_method' object has no attribute '__func__'
基本上,是的,Python确实区分了它们,但在Python中,将方法视为函数的子集是很常见的。 方法与类或实例关联,而“独立函数”则不是。 作为一种方法的东西也是一种功能,但可能有不是方法的功能。
正如Jon Clements在他的评论中提到的那样,这个区别并不像C ++那样铁定。 独立函数可以在运行时“转换”为方法,并且可以将方法分配给变量,使得它们的有效行为与独立函数无异。 所以方法和功能之间的界限是可渗透的。
链接地址: http://www.djcxy.com/p/17305.html