2010-12-03 84 views
7

我在Google上找不到任何关于此主题的内容,所以我想我应该问这里:Python:类似jQuery的函数链接?

是否有可能使用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... 

似乎存在着一些虚假库创建这样的功能,但我似乎无法看到为什么这必须是如此复杂,看起来...

谢谢!

+0

术语是 “连贯接口”。不知道为什么GvR不喜欢他们。 – 2010-12-03 06:28:51

回答

9

这里是西蒙的​​建议的扩展:

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 

你可以去一个更好,并使​​行为完全像使用collections abstract base classes列表。事实上,你可以子集list本身,虽然它可能会限制你做某些事情,你可能需要做...我不知道一般的意见是什么对子类化内置类型list

3

如果我们正在谈论对象方法,那么它是微不足道的,只是从每种方法return self。另一方面,如果你想链接未绑定的函数,那么按照你想要的方式将它们链接起来对我来说并没有意义。当然,它看起来不错,但它在语义上是不连贯的,因为“。”代表对象属性访问,不代表“链”。

+0

嗯,所以你说我*不能*定义这样的功能?我想我必须在它上面使用jQuery并为自己定义一个`L('my','strange','list')`类型的函数。谢谢! – Blender 2010-12-03 06:32:20

+0

就像一个脱离主题的问题,我可以在Python的对象名称中使用哪些特殊字符?我尝试了`$`,但解释器不喜欢那个...... – Blender 2010-12-03 06:33:33

+0

好吧,从技术上讲,你可能可能因为函数也是Python中的对象。一个函数可以有一个自定义属性,它也是一个函数,可以像`func1.func2(args)`一样调用。但这将是一团糟。 – Simon 2010-12-03 06:35:42

10

只要函数返回一个值,就可以链接它。在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) 
1

供将来参考:看看Moka,一个极简主义的函数式编程库。从他们的例子:

(List()     # Create a new instance of moka.List 
    .extend(range(1,20)) # Insert the numbers from 1 to 20 
    .keep(lambda x: x > 5) # Keep only the numbers bigger than 5 
    .rem(operator.gt, 7) # Remove the numbers bigger than 7 using partial application 
    .rem(eq=6)    # Remove the number 6 using the 'operator shortcut' 
    .map(str)    # Call str on each numbers (Creating a list of string) 
    .invoke('zfill', 3)  # Call zfill(x, 3) on each string (Filling some 0 on the left) 
    .insert(0, 'I am')  # Insert the string 'I am' at the head of the list 
    .join(' '))    # Joining every string of the list and separate them with a space. 

>>> 'I am 007' 
0

看看this。这是一个简单的链接封装类。它实现了一些underscore.js库的功能。你用下划线包住你的列表,元组或字典,然后玩它,然后通过追加另一个下划线得到它的值。

print (_([1,2,3]) 
     .map(lambda x: x+1) 
     .reverse() 
     .dict_keys(["a", "b", "c"]) 
     .invert() 
     .items() 
     .append(("this is what you got", "chaining")) 
     .dict()._) 

输出:

{2: 'c', 3: 'b', 4: 'a', 'this is what you got': 'chaining'}