2017年11月23日 星期四

[ Python 文章收集 ] Function Composition in Python

Source From Here 
Preface 
While I don’t consider myself a functional programming guru, all those hours spent in Haskell, Lisp and Scheme definitively changed my way of programming. So, after seeing a lot of unnecessarily complex implementations of function composition in Python on the Web, I decided to write this article to present a simple yet powerful solution that covers all use cases. If you are familiar with function composition, you may want to go to the solution

Composing two functions 
Function composition is a way of combining functions such that the result of each function is passed as the argument of the next function. For example, the composition of two functions f and g is denoted f(g(x))x is the argument of g, the result of g is passed as the argument of f and the result of the composition is the result of f

Let’s define compose2, a function that takes two functions as arguments (f and g) and returns a function representing their composition: 
  1. def compose2(f, g):  
  2.     return lambda x: f(g(x))  
Example: 
>>> def double(x):
... return x * 2
...
>>> def inc(x):
... return x + 1
...
>>> inc_and_double = compose2(double, inc)
>>> inc_and_double(10)
22

Composing n functions 
Now that we know how to compose two functions, it would be interesting to generalize it to accept n functions. Since the solution is based on compose2, let’s first look at the composition of three functions using compose2
>>> def dec(x):
... return x - 1
...
>>> inc_double_and_dec = compose2(compose2(dec, double), inc) # inc > double > dec
>>> inc_double_and_dec(10)
21

Do you see the pattern? First, we compose the first two functions, then we compose the newly created function with the next one and so on. Let’s write this in Python. 
  1. import functools  
  2.   
  3. def compose(*functions):  
  4.     def compose2(f, g):  
  5.         return lambda x: f(g(x))  
  6.     return functools.reduce(compose2, functions, lambda x: x)  
Or in a more compact way: 
  1. def compose(*functions):  
  2.     return functools.reduce(lambda f, g: lambda x: f(g(x)), functions, lambda x: x)  
Example: 
>>> inc_double_and_dec = compose(dec, double, inc)
>>> inc_double_and_dec(10)
21

Note that functools.reduce is also called fold

Multiple-argument functions 
The reason why implementations get complex is because they support multiple-argument functions. But there is no need to do so, because any function can be transformed to a one-argument function using higher-order functions such as functools.partial, decorators or our own functions. 
>>> def second(*args):
... return args[1]
...
>>> def second_wrapper(lst):
... return second(*lst)
...
>>> pipeline = compose(second_wrapper, list, range)
>>> pipeline(5)
1
>>> def sub(a, b):
... return a - b
...
>>> pipeline = compose(functools.partial(sub, b=4), operator.neg)
>>> pipeline(-6)
2

If you want to learn about functional programming in Python, I recommend this document.

沒有留言:

張貼留言

[ Python 文章收集 ] SQLAlchemy quick start with PostgreSQL

Source From   Here   Preface   This is a quick tutorial for getting started with   SQLAlchemy Core API .   Prerequisites   In this quick st...