Python中的函数是对象吗?

38 投票
2 回答
39096 浏览
提问于 2025-04-18 17:10

我经常听到在Python中提到这个说法(比如在装饰器等主题中,当你传递函数时),但从来没有看到过详细的解释。

举个例子,是否可以创建一个类c,它只有一个抽象方法,并且这个方法是用一对开括号和闭括号来调用的。

i.e class c:
       @abstractmethod
       def method_to_be_called_by():
        ... 

这样你就可以有

c(whatever parameters are required)

我可能对这个理解有些偏差,我只是好奇大家对此的看法。

2 个回答

8

一个简单的方法来理解这个问题是,在Python解释器中创建一个函数,比如 def bar(x): return x + 1,然后使用 dir(bar) 来查看这个函数的各种神奇属性,包括 __class__

没错,Python中的函数其实都是完整的对象。

另外一种理解方式是,如果一个对象有一个神奇的 __call__() 方法,那么它就可以被当作函数来使用。

44

你在寻找 __call__ 方法。函数对象是有这个方法的:

>>> def foo(): pass
... 
>>> foo.__call__
<method-wrapper '__call__' of function object at 0x106aafd70>

不过,Python 解释器在遇到 Python 函数对象时,实际上并不会使用这个方法;在大多数情况下,优化后的实现会直接跳到里面的字节码。

但是你 可以 在自己的自定义类中使用这个方法:

class Callable(object):
    def __init__(self, name):
        self.name = name

    def __call__(self, greeting):
        return '{}, {}!'.format(greeting, self.name)

演示:

>>> class Callable(object):
...     def __init__(self, name):
...         self.name = name
...     def __call__(self, greeting):
...         return '{}, {}!'.format(greeting, self.name)
... 
>>> Callable('World')('Hello')
'Hello, World!'

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

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

你可以把这和用字面量语法创建字符串、整数或列表进行比较:

listobject = [1, 'two']

上面的代码创建了 3 个对象,而没有调用任何类型,Python 完全是根据你使用的语法来处理的。函数也是一样的。

自己创建一个函数对象可能会复杂一些;你至少需要有一个代码对象和对全局命名空间的引用:

>>> function_type = type(lambda: None)
>>> function_type
<type 'function'>
>>> function_type(foo.__code__, globals(), 'bar')
<function bar at 0x106d906e0>

在这里,我通过重用 function 类型来创建一个函数对象,使用了 foo 函数的代码对象;函数类型并不是一个内置名称,但这个类型确实存在,可以通过对现有函数实例调用 type() 来获得。

我还传入了我的解释器的全局命名空间和一个名称;后者是一个可选参数;如果没有提供名称,则会从代码对象中获取。

撰写回答