方法和函数之间的区别,在Python中与C ++相比

Difference between methods and functions, in Python compared to C++

我正在编写关于Python的代码学院教程,我对方法和函数的定义有点困惑。从教程中:

You already know about some of the built-in functions we've used on (or to create) strings, such as .upper(), .lower(), str(), and len().

来自C++,我认为EDOCX1 0和EDCOX1,1称为方法,EDOCX1,2,EDCX1,3个函数。在本教程中,这些术语似乎可以互换使用。

Python区分C++中的方法和函数吗?

与方法和函数之间的区别不同,我在询问关于Python的详细信息。术语"方法"和"函数"似乎并不总是遵循链接问题的公认答案中给出的定义。


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

1
2
3
4
5
>>> def a(): pass
>>> a
<function a at 0x107063aa0>
>>> type(a)
<type 'function'>

方法是一个特殊的函数类,可以绑定或取消绑定。

1
2
3
4
5
6
7
8
9
10
11
>>> 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'>

当然,不能调用未绑定的方法(至少不能在不将实例作为参数传递的情况下直接调用):

1
2
3
4
>>> 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如此强大的许多小东西之一。

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

这也意味着,尽管len(...)str(...)之间存在根本区别(后者是类型构造函数),但在深入挖掘之前,您不会注意到区别:

1
2
3
4
>>> len
<built-in function len>
>>> str
<type 'str'>


If you still don’t understand how methods work, a look at the
implementation can perhaps clarify matters. When an instance attribute
is referenced that isn’t a data attribute, its class is searched. If
the name denotes a valid class attribute that is a function object, a
method object is created by packing (pointers to) the instance object
and the function object just found together in an abstract object:
this is the method object. When the method object is called with an
argument list, a new argument list is constructed from the instance
object and the argument list, and the function object is called with
this new argument list.

Ok.

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

Ok.

仔细阅读这段摘录。好的。

它的意思是:好的。

1)一个实例并不真正拥有一个对象,而该对象是一个将成为其属性的方法。实际上,实例的__dict__中根本没有"method"属性(__dict__是对象的名称空间)好的。

2)当调用"method"属性时,一个实例似乎有一个"method",这是由于一个进程,而不是实例的命名空间中存在一个方法对象。好的。

3)另外,在类的名称空间中还没有真正的方法对象。好的。

但是实例有一个区别,因为当这样的调用完成时,一定有某种东西会导致一个真正的方法对象,不是吗?好的。

所谓的类的"方法"属性,为了便于使用,实际上是一个函数对象,它是类名称空间中的属性。也就是说,一对(函数的标识符,函数)是类的__dict__的成员,这个属性允许intepreter在执行方法调用时构造方法对象。好的。

4)同样,当调用"method"属性时,类似乎具有"method"这一事实是由于进程,而不是类的命名空间中存在方法对象。好的。

EDIT I'm no more sure of that; see at the end

Ok.

5)方法对象(不是"方法"对象;我的意思是实际对象实际上是方法`,摘录中描述的内容)是在调用时创建的,它以前不存在。它是一种包装器:它打包指向实例对象和方法所基于的函数对象的指针。好的。

所以,一个方法是基于一个函数的。对于我来说,这个函数是持有上述"方法"的类的真实属性,因为这个函数实际上属于类的名称空间(__dict__:当__dict__被打印时,这个函数被描述为。可以使用别名im_func__func__从方法对象访问此函数(请参见下面的代码)。好的。

.好的。

我相信这些概念不是很常见和理解。但是下面的代码证明了我所说的。好的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
class A(object):
    def __init__(self,b=0):
        self.b = b
    print 'The __init__ object :
'
,__init__

    def addu(self):
        self.b = self.b + 10
    print '
The addu object :
'
,addu


print '
The A.__dict__  items :
'
,
print '
'
.join('  {0:{align}11}  :  {1}'.format(*it,align='^')
                for it in A.__dict__.items())
a1 = A(101)
a2 = A(2002)

print '
The a1.__dict__  items:'

print '
'
.join('  {0:{align}11}  :  {1}'.format(*it,align='^')
                for it in a1.__dict__.items())

print '
The a2.__dict__  items:'

print '
'
.join('  {0:{align}11}  :  {1}'.format(*it,align='^')
                for it in a2.__dict__.items())

print '
A.addu.__func__ :'
,A.addu.__func__
print id(A.addu.__func__),'==',hex(id(A.addu.__func__))
print

print 'A.addu :
  '
,
print A.addu,'
  '
,id(A.addu),'==',hex(id(A.addu))

print 'a1.addu :
  '
,
print a1.addu,'
  '
,id(a1.addu),'==',hex(id(a1.addu))
print 'a2.addu :
  '
,
print a2.addu,'
  '
,id(a2.addu),'==',hex(id(a2.addu))

a2.addu()
print '
a2.b =='
,a2.b

print '
The A.__dict__  items :
'
,
print '
'
.join('  {0:{align}11}  :  {1}'.format(*it,align='^')
                for it in A.__dict__.items())

结果好的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
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__    :  
  __weakref__  :  
    __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__    :  
  __weakref__  :  
    __doc__    :  None
   __init__    :  <function __init__ at 0x011E54B0>

.好的。编辑

有什么事困扰着我,我不知道这个问题的深层次:好的。

以上代码表明,A.addua1.addua2.addu都是同一方法对象,具有唯一的标识。但是,A.addu被称为未绑定方法,因为它没有关于特定实例的任何信息,而a1.addua2.addu是所谓的绑定方法,因为每个方法都有指定该方法操作必须关注的实例的信息。从逻辑上讲,对我来说,这意味着对于这三种情况,方法应该是不同的。好的。

但三者的同一性是相同的,而且这个同一性不同于方法所基于的函数的同一性。它得出的结论是,该方法实际上是内存中的一个对象,并且它不会从一个实例的一个调用更改为另一个实例的另一个CAL。好的。

但是,打印类的名称空间__dict__,即使在创建实例和调用"method"addu()之后,此名称空间也不会向不同于addu函数的方法对象公开可以标识的新对象。好的。

这是什么意思?它给我的印象是,一旦创建了一个方法对象,它就不会被破坏,而是存在于内存(RAM)中。但它是隐藏的,只有形成介子功能的过程才知道如何和在哪里找到它。此隐藏对象(real method对象)必须能够更改对必须应用函数的实例的引用,或者如果作为未绑定方法调用,则可以更改对None的引用。在我看来,这只是一个"头脑风暴"的假设。好的。

有人知道这个审问吗?好的。

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

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

1
2
x = 'hello'
print x.upper.__func__

结果好的。

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

好啊。


在以下类定义中:

1
2
3
4
class MyClass:
   """A simple example class"""
    def f(self):
        return 'hello world'
  • 班级:MyClass
  • 函数:f-()
  • 方法:无(实际不适用)

让我们创建上述类的实例。我们将通过将class object, i.e. MyClass()分配给var x来实现这一点。

1
  x = MyClass()

在这里,

  • 功能:无
  • 方法:x. f-()

别忘了,当我们把x分配给myclass()时,function object MyClass.f被用来定义(内部)method object x.f


基本上,是的,python确实区分了它们,但在python中,通常将方法视为函数的子集。方法与类或实例关联,而"独立函数"则不关联。一个方法也是一个函数,但也有一些函数不是方法。

正如Jon Clements在他的评论中提到的,这个区别并不像C++中那么明显。独立函数可以在运行时"转换"为方法,并且可以将方法分配给变量,使它们的行为与独立函数没有任何不同。所以方法和函数之间的边界是可渗透的。