开发者

Python: jQuery-like function chaining?

开发者 https://www.devze.com 2023-01-28 20:38 出处:网络
I couldn\'t find anything on this subject on Google, so I think I should ask it here: Is it possible to chain functions with Python, like jQuery does?

I couldn't find anything on this subject on Google, so I think I should ask it here:

Is it possible to chain functions with Python, like jQuery does?

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

I am losing a lot of space and readability when开发者_如何学运维 I write this code:

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

There seems to exist some illusive library for creating such functions, but I can't seem to see why this has to be so complicated-looking...

Thanks!


As long as the function returns a value, you can chain it. In jQuery, a selector method usually returns the selector itself, which is what allows you to do the chaining. If you want to implement chaining in python, you could do something like this:

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!

Your problem, however, seems to be that your function arguments are too cramped. Chaining is not a solution to this. If you want to condense your function arguments, just assign the arguments to variables before passing them to the function, like this:

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


Here's an expansion of Simon's ListMutator suggestion:

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

You could go one better and make ListMutator act entirely like a list by using the collections abstract base classes. In fact, you could subclass list itself, although it may restrict you from doing certain things you might need to do... and I don't know what the general opinion is on subclassing built-in types like list.


If we're talking about object methods, then it's trivial, just return self from every method. On the other hand, if you would like to chain unbound functions, it doesn't really make sense to me to chain them the way you want to. Sure, it looks nice, however it's semantically incoherent because the "." stands for object attribute access and not for "chain".


For future reference: have a look at Moka, a minimalist functional programming library. From their examples:

(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'


Take a look at this. It is A simple wrapper class for chaining. And it implemented some of the underscore.js lib's functionality. You wrap your list, tuple or dict with an underscore, and play with it then get the value out of it by appending another underscore.

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()._)

output:

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

精彩评论

暂无评论...
验证码 换一张
取 消