Skip to main content
 首页 » 编程设计

python之如何链接多个参数即加(1)(2)(3) = 6

2025年05月04日10bjzhanghao

我正在尝试创建一个链接多个参数结果的函数。

def hi(string): 
   print(string)<p> 
   return hi 

调用 hi("Hello")("World") 有效,并按预期变为 Hello\n World。

问题是当我想将结果附加为单个字符串时,但是 return string + hi 产生错误,因为 hi 是一个函数。

我已经尝试使用 __str__ 和 __repr__ 来改变 hi 在没有输入时的行为方式。但这只会在其他地方造成不同的问题。

hi("Hello")("World") = "Hello"("World") -> 自然产生错误。

我明白为什么程序无法解决它,但我找不到解决方法。

请您参考如下方法:

你在这里遇到了困难,因为每次调用函数的结果本身必须是可调用的(因此你可以链接另一个函数调用),同时也是一个合法的字符串(以防万一您不链接另一个函数调用并按原样使用返回值)。

幸运的是,Python 已经涵盖了:通过在其上定义 __call__ 方法,任何类型都可以像函数一样可调用。 str 等内置类型没有这样的方法,但您可以定义一个 str 的子类。

class hi(str): 
    def __call__(self, string): 
        return hi(self + '\n' + string) 

这不是很漂亮而且有点脆弱(即,当您对特殊字符串进行几乎所有操作时,您最终将得到常规的 str 对象,除非您覆盖 的所有方法str 来返回 hi 实例),因此不被认为是非常 Pythonic 的。

在这种特殊情况下,如果您在开始使用结果时以常规 str 实例结束并不重要,因为此时您已经完成了链接函数调用,或者应该是在任何理智的世界。但是,在通过子类化向内置类型添加功能的一般情况下,这通常是一个问题。

大致上,您标题中的问题可以类似地回答:

class add(int):    # could also subclass float 
    def __call__(self, value): 
        return add(self + value) 

但是,要真正正确地执行 add(),您希望能够返回结果类型的可调用子类,无论它是什么类型;它可能是 int 或 float 之外的东西。我们可以根据结果类型动态创建它们,而不是尝试对这些类型进行分类并手动编写必要的子类。这是一个简单的版本:

class AddMixIn(object): 
     def __call__(self, value): 
         return add(self + value) 
 
def add(value, _classes={}): 
    t = type(value) 
    if t not in _classes: 
        _classes[t] = type("add_" + t.__name__, (t, AddMixIn), {}) 
    return _classes[t](value) 

令人高兴的是,这个实现对字符串工作得很好,因为它们可以使用 + 连接起来。

一旦开始执行此操作,您可能也想对其他操作执行此操作。每次操作都是拖拽复制粘贴基本相同的代码,那就写个功能给你写吧!只需指定一个实际执行工作的函数,即获取两个值并对它们执行某些操作,它就会返回一个为您完成所有类修改的函数。您可以使用 lambda(匿名函数)或预定义函数指定操作,例如来自 operator 模块的函数。由于它是一个接受一个函数并返回一个函数(嗯,一个可调用对象)的函数,它也可以用作装饰器!

 def chainable(operation): 
 
     class CallMixIn(object): 
         def __call__(self, value): 
             return do(operation(self, value)) 
 
     def do(value, _classes={}): 
         t = type(value) 
         if t not in _classes: 
             _classes[t] = type(t.__name__, (t, CallMixIn), {}) 
         return _classes[t](value) 
 
     return do 
 
 add = chainable(lambda a, b: a + b) 
 
 # or... 
 import operator 
 add = chainable(operator.add) 
 
 # or as a decorator... 
 @chainable 
 def add(a, b): return a + b 

最后它仍然不是很漂亮而且仍然有点脆弱而且仍然不会被认为是非常 Pythonic。

如果您愿意使用额外的(空)调用来表示链的结束,事情会变得简单得多,因为您只需要返回函数,直到您被无参数调用为止:

def add(x): 
    return lambda y=None: x if y is None else add(x+y) 

你可以这样调用它:

add(3)(4)(5)()    # 12