Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

method chaining in python

(not to be confused with itertools.chain)

I was reading the following: http://en.wikipedia.org/wiki/Method_chaining

My question is: what is the best way to implement method chaining in python?

Here is my attempt:

class chain():     def __init__(self, my_object):         self.o = my_object      def __getattr__(self, attr):         x = getattr(self.o, attr)         if hasattr(x, '__call__'):             method = x             return lambda *args: self if method(*args) is None else method(*args)         else:             prop = x             return prop  list_ = chain([1, 2, 3, 0]) print list_.extend([9, 5]).sort().reverse()  """ C:\Python27\python.exe C:/Users/Robert/PycharmProjects/contests/sof.py [9, 5, 3, 2, 1, 0] """ 

One problem is if calling method(*args) modifies self.o but doesn't return None. (then should I return self or return what method(*args) returns).

Does anyone have better ways of implementing chaining? There are probably many ways to do it.

Should I just assume a method always returns None so I may always return self.o ?

like image 478
robert king Avatar asked Aug 29 '12 07:08

robert king


People also ask

What do you mean by method chaining?

Method chaining, also known as named parameter idiom, is a common syntax for invoking multiple method calls in object-oriented programming languages. Each method returns an object, allowing the calls to be chained together in a single statement without requiring variables to store the intermediate results.

What is chaining in pandas?

Pandas chaining is an alternative to variable assignment when transforming data. Those in favor of chaining argue that the code is easier to read because it lays out the execution of the transformation like a recipe.

What does __ call __ do in Python?

The __call__ method enables Python programmers to write classes where the instances behave like functions and can be called like a function. When the instance is called as a function; if this method is defined, x(arg1, arg2, ...) is a shorthand for x.


2 Answers

There is a very handy Pipe library which may be the answer to your question. For example::

seq = fib() | take_while(lambda x: x < 1000000) \             | where(lambda x: x % 2) \             | select(lambda x: x * x) \             | sum() 
like image 151
Zaur Nasibov Avatar answered Oct 04 '22 11:10

Zaur Nasibov


It's possible if you use only pure functions so that methods don't modify self.data directly, but instead return the modified version. You also have to return Chainable instances.

Here's an example using collection pipelining with lists:

import itertools  try:     import builtins except ImportError:     import __builtin__ as builtins   class Chainable(object):     def __init__(self, data, method=None):         self.data = data         self.method = method      def __getattr__(self, name):         try:             method = getattr(self.data, name)         except AttributeError:             try:                 method = getattr(builtins, name)             except AttributeError:                 method = getattr(itertools, name)          return Chainable(self.data, method)      def __call__(self, *args, **kwargs):         try:             return Chainable(list(self.method(self.data, *args, **kwargs)))         except TypeError:             return Chainable(list(self.method(args[0], self.data, **kwargs))) 

Use it like this:

chainable_list = Chainable([3, 1, 2, 0]) (chainable_list     .chain([11,8,6,7,9,4,5])     .sorted()     .reversed()     .ifilter(lambda x: x%2)     .islice(3)     .data) >> [11, 9, 7] 

Note that .chain refers to itertools.chain and not the OP's chain.

like image 24
reubano Avatar answered Oct 04 '22 11:10

reubano