哪个更基础:Python函数或Python对象方法?

时间:2009-12-31 14:31:52

标签: python function object

我试图从概念上理解Python函数和方法的本质。我得到的函数实际上是对象,使用在执行函数时调用的方法。但是,函数对象方法实际上是另一个函数吗?

例如:

def fred():
    pass

如果我查看dir(fred),我会看到它有一个名为__call__的属性。但dir(fred.__call__) 还有一个名为__call__的属性。 fred.__call__.__call__等也是如此。这个__call__对象链的ID表明它们都是截然不同的。它们真的是对象还是解释器的一些低级技巧?

哪个更基础:函数或对象方法?

3 个答案:

答案 0 :(得分:4)

简短回答:两者都是基本的,.__call__()关于函数只是一个虚拟技巧。


这个答案的其余部分有点复杂。你不必理解它,但我觉得这个主题很有趣。请注意,我将提出一系列谎言,逐步修复它们。

答案很长

在最基础的层面上,Python可以说只有2个操作:

  • 属性访问权限:obj.attr
  • 函数调用:callable(args)

方法调用 - obj.method(args) - 不是基本的。它们包含两个步骤:获取属性obj.method(提供可调用的“绑定方法”对象)并使用args调用该属性。

其他运营商就其定义。例如。 x + y尝试x.__add__(y),如果不起作用,则回退到其他类似的组合。

无限长的答案?

到目前为止一切顺利。但是调用和属性访问本身也是根据obj.__call__(args)obj.__getattribute__(name)定义的?!?
它是乌龟一路下来的吗?!?

诀窍是对象上的操作是通过调用类型的方法来定义的:type(obj).__call__(obj, args)type(obj).__getattribute__(obj, name)。哪个BTW意味着我欺骗了你,并且还有第三个基本操作:

  • 获取对象的类型:type(obj)

好的,这仍然没有帮助。 type(obj).__call__(...)仍然涉及属性访问和通话,因此这应该无限期地继续?问题是最终你遇到了一个内置类型 - 通常是一个函数,objecttype - 对于它们,属性访问和函数调用基本

因此,当您调用自定义类的实例时,确实是通过其__call__方法实现的。但它的__call__方法可能是一个正常的函数 - 可以直接调用。神秘的结束。

类似于__getattribute__ - 你可以为它提供 define 属性访问权限,但是类本身实现了属性访问(除非它有一个自定义元类)。

男人面前的帷幕

那为什么即使一个函数有一个fred.__call__方法呢?嗯,这只是吸引力来反映内置类型和自定义类之间的差异。这个方法存在于所有可调用对象上,但调用普通函数不必经过它 - 函数基本上是可调用的。

同样,所有对象都有obj.__getattribute__obj.__class__,但对于内置类型,只需公开基本操作,而不是定义

小字体

第一个声称Python有两个基本操作的说法实际上是一个完全的谎言。从技术上讲,所有Python运算符在C级别都有一个“基本”操作,通过方法公开一致性,而自定义类可以通过类似的方法重新定义这些操作。

但我告诉你的故事可能是真的,它减少了问题的中心:为什么.__call__().__getattribute__()不是无限递归。

答案 1 :(得分:2)

不是特定的Python答案,但在最低级别,处理器只能理解操作和变量。从那里我们推断出函数,从变量和函数我们推断出对象。因此,从低级编程的角度来看,我会说更重要的是函数。

对于Pythonic意义上的Python来说,这不一定是正确的,并且可能是一个很好的例子,说明为什么用它来深入研究语言的实现并不总是有益的。 :)将函数视为对象当然是Python本身更好的答案。

起初我认为你的调用是跟踪Python库的,但.call方法与任何其他方法具有相同的属性。因此,我认为,它使用python CLI进行了几分钟的递归探索。我认为这是探索体系结构的一种痛苦方式,而不一定是Python处理对象的属性的错误。 :)

答案 2 :(得分:1)

  

哪个更基本:功能   或对象方法?

我认为最好的答案可能是“不”。请参阅Python参考的Execution model部分,其中引用“块”。这是实际执行的内容。你在无限搜索结束时遇到的__call__事件只是一个知道如何执行代码块的包装器(参见函数的各种func_xxx属性,而不是实际的字节码存储为func_code)。

同样相关的是Function definitions部分,它引用了“一个函数对象[是](函数的可执行代码的包装器)”。最后,有callable这个词,也可能是“哪个更基本?”的答案。