Python函数对象是否为函数?

2024-04-20 08:46:00 发布

您现在位置:Python中文网/ 问答频道 /正文

我们都知道函数也是对象。但是函数对象与函数相比如何呢?函数对象和函数之间有什么区别?你知道吗

所谓函数对象,我指的是这样定义的g:

class G(object):
    def __call__(self, a):
        pass
g = G()

我所说的函数是指:

def f(a):
    pass

Tags: 对象函数self定义objectdefpasscall
2条回答

使用def语句或lambda表达式时,Python会为您创建函数对象:

>>> def foo(): pass
... 
>>> foo
<function foo at 0x106aafd70>
>>> lambda: None
<function <lambda> at 0x106d90668>

因此,无论何时在python中定义函数,都会创建这样的对象。函数定义没有简单的方法。你知道吗

TL;DR任何实现__call__的对象都可以被调用,例如:函数、自定义类等。。你知道吗

稍长版本:(w全部oft分机

对于您提出的关于有什么不同的问题,完整的答案在python虚拟机的实现中,因此我们必须看看python的幕后黑手。首先是代码对象的概念。Python会将您所抛出的任何东西解析为它自己的内部语言,这种语言在所有被称为字节码的平台上都是相同的。一个非常直观的表示是,当您在导入您编写的自定义库之后获得一个.pyc文件时。这些是pythonvm的原始指令。忽略这些指令是如何从源代码创建的,然后由Python/ceval.c中的PyEval_EvalFrameEx执行。源代码有点像野兽,但最终就像一个简单的处理器,将一些复杂的部分抽象掉。字节码是这个处理器的汇编语言。特别地,这个“处理器”的“操作码”之一是(恰当地命名)CALL_FUNCTION。回调经过多次调用,最终到达PyObject_Call()。此函数获取指向PyObject的指针,并从其类型中提取^{}属性并直接调用它(从技术上讲,它会检查它是否首先在那里):

...
call = func->ob_type->tp_call //func is an arg of PyObject_Call() and is a pointer to a PyObject
...
result = (*call)(func, arg, kw);

任何实现__call__的对象都被赋予一个tp_call属性,并带有指向实际函数的指针。我相信这是由Objects/typeobject.c中的slotdefs[]定义处理的:

FLSLOT("__call__", tp_call, slot_tp_call, (wrapperfunc)wrap_call,
       "__call__($self, /, *args, **kwargs)\n \n\nCall self as a function.",
       PyWrapperFlag_KEYWORDS)

函数的__call__方法本身是在cpython实现中定义的,它定义了python VM应该如何开始执行该函数的字节码,以及应该如何返回数据(如果有的话)。当您给一个任意类一个__call__方法时,属性是一个函数对象,它再次引用了__call__的cpython实现。因此,当您调用一个“普通”函数时foo.__call__被引用。调用可调用类时,self.__call__等价于foo,实际调用的cpython引用是self.__call__.im_func.__call__。你知道吗

免责声明

对我来说,这是一次进入未知领域的旅程,我完全有可能曲解了实现的一些细节。我主要从this的博客文章中获取关于python callables如何在引擎盖下工作的信息,并通过python source code挖掘了一些我自己的信息

相关问题 更多 >