Python: 类jQuery的函数链式调用?

9 投票
5 回答
7508 浏览
提问于 2025-04-16 07:58

我在谷歌上找不到关于这个主题的任何信息,所以我想在这里问一下:

在Python中,能像jQuery那样把多个函数连在一起使用吗?

['my', 'list'].foo1(arg1, arg2).foo2(arg1, arg2).foo3(arg1, arg2) #etc...

我写的代码占用了很多空间,而且可读性也不高:

foo3(foo2(foo1(['my', 'list'], arg1, arg2), arg1, arg2), arg1, arg2) #etc...

似乎有一些神秘的库可以用来创建这样的函数,但我不明白为什么这看起来要这么复杂...

谢谢!

5 个回答

3

如果我们在讨论对象的方法,那就很简单了,只需要在每个方法里写上 return self 就可以了。另一方面,如果你想把不属于任何对象的函数连在一起,我觉得这样连起来没有什么意义。虽然看起来不错,但从语义上来说,这样用不太合适,因为“.”这个符号是用来访问对象的属性,而不是用来表示“连锁”的。

11

只要函数能返回一个值,你就可以进行链式调用。在jQuery中,选择器方法通常会返回选择器本身,这就是你可以进行链式调用的原因。如果你想在Python中实现链式调用,可以这样做:

class RoboPuppy:

  def bark(self):
    print "Yip!"
    return self

  def growl(self):
    print "Grr!"
    return self

pup = RoboPuppy()
pup.bark().growl().bark()  # Yip! Grr! Yip!

不过,你的问题似乎是你的函数参数太紧凑了。链式调用并不是解决这个问题的方法。如果你想简化函数参数,可以在把参数传给函数之前,先把它们赋值给变量,像这样:

spam = foo(arg1, arg2)
eggs = bar(spam, arg1, arg2)
ham = foobar(eggs, args)
10

这是对西蒙的 ListMutator 建议的进一步扩展:

class ListMutator(object):

    def __init__(self, seq):
        self.data = seq

    def foo1(self, arg1, arg2):
        self.data = [x + arg1 for x in self.data]
        # This allows chaining:
        return self

    def foo2(self, arg1, arg2):
        self.data = [x*arg1 for x in self.data]
        return self

if __name__ == "__main__":
    lm = ListMutator([1,2,3,4])
    lm.foo1(2, 0).foo2(10, 0)
    print lm.data

    # Or, if you really must:
    print ListMutator([1,2,3,4]).foo1(2, 0).foo2(10, 0).data

你可以更进一步,让 ListMutator 完全像一个列表一样工作,方法是使用 集合抽象基类。实际上,你可以直接继承 list,不过这样可能会限制你做某些你需要的事情……而且我不知道大家对继承像 list 这样的内置类型的看法是什么。

撰写回答