为什么Python中有可调用对象?
可调用对象的目的是什么?它们解决了什么问题?
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__
这个方法,那它只是众多特殊方法中的一个,这些特殊方法可以让你改变自定义对象的行为,比如进行数学运算,或者定义当你“调用”一个对象时会发生什么。
使用这种方式的一个想法是创建一个工厂对象,这个工厂对象可以用来生成其他对象。