Python中的函数是对象吗?
我经常听到在Python中提到这个说法(比如在装饰器等主题中,当你传递函数时),但从来没有看到过详细的解释。
举个例子,是否可以创建一个类c
,它只有一个抽象方法,并且这个方法是用一对开括号和闭括号来调用的。
i.e class c:
@abstractmethod
def method_to_be_called_by():
...
这样你就可以有
c(whatever parameters are required)
我可能对这个理解有些偏差,我只是好奇大家对此的看法。
2 个回答
一个简单的方法来理解这个问题是,在Python解释器中创建一个函数,比如 def bar(x): return x + 1
,然后使用 dir(bar)
来查看这个函数的各种神奇属性,包括 __class__
。
没错,Python中的函数其实都是完整的对象。
另外一种理解方式是,如果一个对象有一个神奇的 __call__()
方法,那么它就可以被当作函数来使用。
你在寻找 __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()
来获得。
我还传入了我的解释器的全局命名空间和一个名称;后者是一个可选参数;如果没有提供名称,则会从代码对象中获取。