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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/20981789/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-18 21:41:50  来源:igfitidea点击:

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

pythonfunctionoopmethods

提问by Q-bertsuit

I'm doing Code Academy's tutorials on Python, and I'm a bit confused about the definition of method and function. From the tutorial:

我在做代码学院关于 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().

你已经知道了一些内置的功能,我们使用(或创建)的字符串,例如.upper().lower()str(),和len()

Coming from C++, I would think .upper()and .lower()would be called methods and len()and str()functions. In the tutorial, the terms seem to be used interchangeably.

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

Does Python distinguish between methods and functions in the way C++ does?

Python 是否像 C++ 那样区分方法和函数?

Unlike Difference between a method and a function, I'm asking about the particulars of Python. The terms 'method' and 'function' do not seem to always follow the definition given in the accepted answer of the linked question.

方法和函数之间的差异不同,我在询问 Python 的细节。术语“方法”和“函数”似乎并不总是遵循链接问题的公认答案中给出的定义。

采纳答案by Krumelur

A functionis a callable object in Python, i.e. can be called using the call operator(though other objects can emulate a function by implementing __call__). For example:

功能是在Python一个可调用对象,即,可以使用被称为呼叫操作员(尽管其它的目的可以通过实施模拟函数__call__)。例如:

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

A methodis a special class of function, one that can be boundor unbound.

方法是一类特殊的功能,一个可被结合绑定

>>> 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'>

Of course, an unbound method cannot be called (at least not directly without passing an instance as argument):

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

>>> 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)

In Python, in most cases you won't notice the difference between a bound method, a function or a callable object (i.e. an object that implements __call__), or a class constructor. They all look the same, they just have different naming conventions. Under the hood, the objects may look vastly different though.

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

This means that a bound method can be used as a function, this is one of the many small things that makes Python so powerful

这意味着绑定方法可以用作函数,这是使 Python 如此强大的众多小东西之一

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

It also means that even though there is a fundamental difference between len(...)and str(...)(the latter is a type constructor), you won't notice the difference until you dig a little deeper:

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

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

回答by BrenBarn

Basically, yes, Python does distinguish them, but in Python it is common to view methods as a subset of functions. Methods are associated with a class or instance, and "standalone functions" are not. Something that is a method is also a function, but there can be functions that are not methods.

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

As Jon Clements mentioned in his comment, though, the distinction is not so ironclad as in C++. Standalone functions can be "converted" into methods at runtime, and methods can be assigned to variables in such a way that they effectively behave no differently than standalone functions. So the boundary between methods and functions is permeable.

然而,正如 Jon Clements 在他的评论中提到的,这种区别并不像在 C++ 中那么铁定。独立函数可以在运行时“转换”为方法,并且方法可以以这样一种方式分配给变量,即它们的有效行为与独立函数没有区别。所以方法和函数之间的界限是可以渗透的。

回答by eyquem

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.

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

如果您仍然不了解方法的工作原理,那么查看实现也许可以澄清问题。当引用的实例属性不是数据属性时,将搜索其类。如果名称表示作为函数对象的有效类属性,则通过打包(指向)实例对象和刚刚在抽象对象中一起找到的函数对象来创建方法对象:这就是方法对象。当使用参数列表调用方法对象时,会根据实例对象和参数列表构造一个新的参数列表,并使用这个新的参数列表调用函数对象。

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

Read carefully this excerpt.

仔细阅读这段摘录。

It means :

它的意思是 :

1) An instance doesn't really hold an object being a method that would be its attribute.
In fact, there is not at all a "method" attribute in the __dict__of an instance (__dict__is the namespace of an object)

1) 一个实例并没有真正将一个对象作为一个方法,作为它的属性。
实际上,__dict__实例的(__dict__是对象的命名空间) 中根本没有“方法”属性

2) The fact that an instance seems to have a "method" when a "method" attribute is called, is due to a process, not the presence of a method object inside the namespace of an instance

2) 当一个“方法”属性被调用时,一个实例似乎有一个“方法”的事实是由于一个过程,而不是一个实例的命名空间内的方法对象的存在

3) Also, there doesn't really exist a method object in the namespace of a class.

3)此外,在类的命名空间中并不真正存在方法对象。

But there's a difference with an instance, because there must be somewhere something that leads to a real method object when such a call is done, must not ?

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

What is called a "method" attribute of a class, for easiness of wording, is in reality a functionobject being attribute in the namespace of the class.
That is to say, a pair (identifier of the function, function)is a member of the __dict__of a class, and this attribute allows the intepreter to construct a method object when a method call is performed.

为便于表述,所谓的类的“方法”属性实际上是作为类名称空间中的属性的函数对象。
也就是说,pair (函数的标识符,函数)是一个__dict__类的成员,这个属性允许解释器在进行方法调用时构造一个方法对象。

4) Again, the fact that a class seems to have a "method" when a "method" attribute is called, is due to a process, not to the presence of a method object inside the namespace of a class

4) 同样,当一个“方法”属性被调用时,一个类似乎有一个“方法”的事实是由于一个过程,而不是一个类的命名空间内的方法对象的存在

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

编辑我不再确定了;见最后

5) A method object (not "method" object; I mean the real object being really a method`, what is described in the excerpt) is createdat the moment of the call, it doesn't exists before.
It is a kind of wrapper : it packs pointers to the instance object and the function object on which the method is based.

5)一个方法对象(不是“方法”对象;我的意思是真正的对象实际上是一个方法,摘录中描述的)在调用的那一刻被创建,它之前不存在。
它是一种包装器:它将指向实例对象和方法所基于的函数对象的指针打包。

So, a method is based on a function. This function is for me the real attribute of the class holding the said "method", because this function really belongs to the namespace ( __dict__) of the class: this function is described as a <function ......>when the __dict__is printed.
This function can be reached from the method object using the alias im_funcor __func__(see the below code)

所以,方法是基于函数的。这个函数对我来说是持有所说“方法”的类的真正属性,因为这个函数确实属于__dict__类的命名空间():这个函数<function ......>__dict__打印时被描述为 a 。
可以使用别名im_func或从方法对象访问此函数__func__(请参阅下面的代码)

.

.

I believe that these notions are not very commonly known and understood. But the following code proves what I said.

我相信这些概念并不是很广为人知和理解。但是下面的代码证明了我所说的。

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())

result

结果

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>

.

.

EDIT

编辑

Something is troubling me and I don't know the deep innards of the subject:

有些事情困扰着我,我不知道这个主题的深层内幕:

The above code shows that A.addu, a1.adduand a2.adduare all the same method object, with a unique identity.
However A.adduis said an unbound method because it doesn't have any information concerning an particular instance,
and a1.adduand a2.adduare said bound methods because each one has information designating the instance that must be concerned by the operations of the method.
Logically, for me, that would mean that the method should be different for each of these 3 cases.

上面的代码表明A.addua1.addua2.addu都是相同的方法对象,具有唯一标识。
不过A.addu据说一个未绑定的方法,因为它没有涉及的特定实例的任何信息,
a1.addua2.addu据说绑定方法,因为每个人都有指定的信息必须由该方法的操作中涉及的实例。
从逻辑上讲,对我来说,这意味着对于这 3 种情况中的每一种,方法都应该不同。

BUTthe identity is the same for all three, and moreover this identity is different from the identity of the function on which the method is based.
It leads to the conclusion that the method is really an object living in the memory, and that it doesn't change from one call from an instance to another cal from another instance.

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

HOWEVER, printing the namespace __dict__of the class, even after the creation of instances and the call of the "method" addu(), this namespace doesn't exposes a new object that could be identified to the method object different from the addufunction.

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

What does it mean ?
It gives me the impression that as soon as a method object is created, it isn't destroyed, it lives in the memory (RAM).
But it lives hidden and only the processes that form the interpeter's functionning know how and where to find it.
This hidden object, the real method object, must have the ability to change the reference to the instance to which the function must be applied, or to reference Noneif it is called as an unbound method. That's what it seems to me, but it's only brain-storming hypothesis.

这是什么意思 ?
它给我的印象是方法对象一被创建,它就不会被销毁,它就存在于内存 (RAM) 中。
但它是隐藏的,只有形成 interpeter 功能的进程才知道如何以及在哪里找到它。
这个隐藏的对象,真正的方法对象,必须能够改变对必须应用函数的实例的引用,或者None如果它作为未绑定的方法被调用,则可以引用。在我看来就是这样,但这只是头脑风暴的假设。

Does anybody know something on this interrogation ?

有人对这次审讯有所了解吗?



To answer to the question, it can be considered correct to call .upperand .lowerfunctions, since in reality they are based on functionsas every method of a class.

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

However, the following result is special, probably because they are builtin methods/functions, not user's methods/functions as in my code.

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

x = 'hello'
print x.upper.__func__

result

结果

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

回答by Ketan

In the following class definition:

在以下类定义中:

class MyClass:
    """A simple example class"""
    def f(self):
        return 'hello world'
  • Class: MyClass
  • Function: f()
  • Method: None (Actually, not applicable)
  • MyClass的
  • 函数f()
  • 方法无(实际上,不适用)

Lets create an instance of the above class. We'll do this by assigning class object, i.e. MyClass()to var x

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

  x = MyClass()

Here,

这里,

  • Function: None
  • Method: x.f()
  • 功能
  • 方法xf()

And lets not forget that the function object MyClass.fwas used to define (internally) the method object x.fwhen we assigned x to MyClass()

并且不要忘记当我们将 x 分配给 MyClass() 时function object MyClass.f, 用于定义(内部method object x.f