2010-12-03 81 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'}