Python Note 3 -FP

Python is not a functional programming language and does not encourage a total FP approach.
However, it did incorporate some handy tools from FP languages to assist us.

High-order function

map(func_1arg, iterable)

exert func on each element of the iterable one by one,
and return an iterator containing all the values func returns.

reduce(func_2rg, iterable)

exert func on iterable[0] and iterable[1],
remember the value returned,
and then exert func on the value returned and iterable[2]
so on so forth,
finally return the final result.
Note that we have to from functools import reduce.

filter(func_bool, iterable)

exert func on each element of the iterable one by one,
remove the element with which func returns False,
do nothing with the element with which func returns True,
returns an iterator containing the remaining values

sorted(iterable, key=None, reverse=False)

exert key function on every element of the iterable,
arrange these elements in the ascending order of its corresponding return value.
or descending order if reverse=True.
Note that we must use keyword arguments for key and reverse.

lambda expression

lambda arguments: return_value

In the place of return_value, there can also be something like print() that returns None.
Note that:
– Normally we only use lambda expression when only one line of code is needed in the function.
– But there are evil trick that allow us to do more with a lambda function.

Closure

The purpose of using a closure is to customize a function by altering the constants within it.
In the definition of function outer(), if we define another function inner() and return it in the end of function outer(), we will create a closure.
Function inner() has access to local variables within function outer(), but only the latest version of these variables.
So if we want to use a loop variable or a variable that changes, we need double closure.

Decorator

A decorator that takes no argument:

import functools

def deco_name(func):
@functools.wraps(func)
def wrapper(*args, **kw):
# Do sth here
return func(*args, **kw)
return wrapper

@deco_name
def decorated_func(sth):

A decorator that takes arguments:

import functools

def deco_name(parameter):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kw):
# Do sth using the parameter
return func(*args, **kw)
return wrapper
return decorator

@deco_name(parameter)
def decorated_func(sth):

The reason why we need that line of @functools.wraps(func) is that it changes decorated_func.__name__ from “wrapper” or “decorator” to its original name “decorated_func”.

“*” notation and function definition

“*” in function definition

  1. def func(*arg) means that func() takes an arbitrary number of parameters and stores them in tuple arg.
  2. def func(**kwarg) means that func() takes an arbitrary number of parameters and stores them in dictionary kwarg.
  3. def func(arg1, arg2, *, kwarg1, kwarg2) means that arguments before “*” are regular arguments, and those after “*” are keyword arguments. Note that if there is a *arg already, arguments after it will automatically be considered as keyword arguments.

“*” when calling a function

  1. To invoke func(*list_or_tuple) converts the list or tuple into a series of arguments.
  2. To invoke func(**dict) converts the dict into a series of keyword arguments.

special notes

  1. Default arguments of a function must be immutable objects, or else it could be altered inside the function and appear different every time we use it.
  2. The difference between regular arguments and keyword arguments:
    For example, if def func(arg1, arg2, *, kwarg1, kwarg2), we must invoke func as func(1, 2, kwarg1=3, kwarg2=4) instead of func(1, 2, 3, 4).
    Keyword arguments can ensure that the users know what they are doing.

Partial function

For a function that takes multiple arguments, if we want to hold some of its arguments constant, we can create a partial function.

import functools
int_base2 = functools.partial(int, base=2)

>>> int_base2('1000000')
64

Note that partial function only sets the value that we want to hold as default value for the function. This means that we can still change it.

>>> int_base2('1000000', base=10)
1000000
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Blog at WordPress.com.

Up ↑

%d bloggers like this: