为什么Python中有可调用对象?

12 投票
3 回答
7829 浏览
提问于 2025-04-15 20:22

可调用对象的目的是什么?它们解决了什么问题?

3 个回答

2

在某些地方,特别是“函数调用函数的函数”这种情况,使用对象可以减少嵌套的层数。

想象一下,创建一个经典的装饰器,它在调用一个函数之前检查一下授权级别。使用起来很简单明了:

@check_authorization(level="Manager")
def update_price(Item, new_price):...

你可以用嵌套函数来实现这个:

def check_authorization(level):
     def take_params(function):
         def concrete(*args, **kwargs):
             if user_level_greater_than(level):
                 return function(*args, 
                     **kwargs)
             return None
         return concrete
     return take_params

或者你也可以用一个类来实现,这样可能会更清晰:

  class check_authorization(object):
      def __init__(level):
         self.level = level
      def __call__(function):
          self.function = function
          return self.dec
      def dec(self, *args, **kwargs):
          if user_level_greater_than(self.level):
             return self.function(*args,v**kwargs)
          return None

很多人会觉得这种扁平化的方法更容易理解。当然,我相信有时候可以“作弊”,因为我喜欢签名和元数据都正确:

from dectools.dectools import make_call_if

@make_call_if
def check_authorization(function, arg, kwargs, level):
    return user_level_greater_than(level)

可调用对象是一种工具,对于一些已知的应用场景非常好,也可能适用于生活中那些奇怪的问题。

13

在Python中,有很多种对象是可以被调用的,它们可以用来做很多事情:

  • 函数是可以被调用的,它们可能会带着来自外部函数的“闭包”。
  • 类也是可以被调用的,调用一个类会得到这个类的一个实例。
  • 方法是可以被调用的,专门用于与某个实例相关的功能。
  • 静态方法和类方法也是可以被调用的,它们的功能是与“整个类”有关的(静态方法的用处有点可疑,因为类方法也能做到同样的事情;-)。
  • 生成器是可以被调用的,调用一个生成器会得到一个迭代器对象。
  • 最后,这可能正是你想问的(没意识到上面提到的都是对象...!!!),你可以编写一个类,使得它的实例是可以被调用的:这通常是更新实例状态并依赖于它的最简单方法(虽然带有合适闭包的函数和绑定方法也可以作为替代方案,但当你需要在同一个对象上同时进行调用其他特定操作时,可调用的实例是唯一的选择:例如,你想要一个既可以调用又可以进行索引的对象,最好是一个既可调用又可索引的类的实例;-)。

Python的标准库提供了很多例子,展示了这些对象可以解决的各种“问题”,其中包含了我上面提到的每种特定类型的许多案例。

9

它们接受一些参数,然后根据这些参数返回结果。

可调用对象其实就是一种抽象的函数形式,或者说是一个接口,定义了一个对象可以像函数一样工作(也就是说,它可以接受参数)。

因为函数本身就是一种特殊的对象,所以很明显,函数也是可调用的对象。如果你在说__call__这个方法,那它只是众多特殊方法中的一个,这些特殊方法可以让你改变自定义对象的行为,比如进行数学运算,或者定义当你“调用”一个对象时会发生什么。

使用这种方式的一个想法是创建一个工厂对象,这个工厂对象可以用来生成其他对象。

撰写回答