First-class Objects
Functions in python area first-class objects:
- created at runtime
- assigned to a variable or element in a data structure
- passed as an argument to function
- returned as the result of a function
Treating a function like an object
1 | def factorial(n): |
Higher-order Functions
A function that takes a function as argument or returns a function as result is a higher-order function. e.g. map function.
1 | fruits = ['strawberry', 'fig', 'apple', 'cherry', 'raspberry', 'banana'] |
Modern replacements for map, filter, and reduce
Functional languages commonly offer the map, filter and reduce higher-order functions.1
2
3
4
5
6
7
8
9#python 2.7
map(fact, filter(lambda n: n % 2, range(5)))
# output => [1, 6]
# python 3.5
map(fact, filter(lambda n: n % 2, range(5)))
# ouput => <map object at 0x7f6ac35e5e10>
list(map(fact, filter(lambda n: n % 2, range(5))))
# output => [1, 6]
In python 3, map and filter return generators – a form of iterator, so their direct substitute is now a generator expression.
In python 2, map and filter return lists, therefore their closest alternative is a listcomp
The reduce function was demoted from a built-in in python 2 to the functools module in python 3. Its most common use case, summation, is better served by the sum built-in available since python 2.3.
1 | # python 2.7 |
Anonymous Functions
The lambda keyword creates an anonymous function within a python expression. The simple syntax of python limits the body of lambda functions to be pure expressions. In other words, the body of a lambda cannot make assignments or use any other python statement such as while, try etc.
The lambda syntax is just syntactic sugar: a lambda expression creates a function object just like the def statement.
The seven flavors of callable objects
The call operator, i.e. (), may be applied to other objects beyond user-defined functions. To determine whether an objects is callable, use the callable() built-in function.
The python Data Model documentation lists seven callable types:
User-defined functions
create with def statements or lambda expressions.
Built-in functions
a function implemented in C (for CPython), like len or time.strftime
Built-in methods
methods implemented in C, like dict.get.
Methods
functions defined in the body of a class.
Classes
when invoked, a class runs its new method to create an instance, then init to initialize it, and finally the instance is returned to the caller.
Class instances
if a class defines a call method, then its instances may be invoked as functions.
Generator functions
functions or methods that use the yield keyword. Then called, generator functions return a generator object.
1 | def test(): |
Function introspection
Functions objects have many attributes. Using built-in function dir(), we can revals all the attributes of a object.
1 | dir(abs) |
From positional to keyword-only paramters
One of the best features of python functions is the extremely flexible parameter handling mechanism, enhanced with keywords-only argumetns in python 3. Closely related are the use of * and ** to “explode” iterables and mappings into seperate arguments when we call a function.
1 | def tag(name, cls=None, *content, **attrs): |
Function Annotaions
Python 3 provides syntax to attach metadata to the paramters of a function declaration and its return value.
1 | # python 3.5 |
Each argument in the function declaration may have an annotation expression preceded by “:”. If there is a default value, the annotation goes between the argument name and the = sign. To annotate the return value, add -> and another expression between th ) and the : at the tail of the function declaration.
The only thing python does with annotations is to store them in the annotation attribute of the function. Nothing else: no checks, enforcement, validation, or any other actions is performed.
Packages for functional programing
The operator module
Often in functional programming it is convenient to use an arithmetic operator as a function.
1 | from operator import mul |
itemgetter: it is function to pick items from sequences.
1 | metro_data = [ |
A sibling of itemgetter is attrgetter, which creates functions to extract object attributes by name.
1 | dc = {'name': 'feifeiyu'} |
methodcaller: it creates calls a method by name on the object given as argument
1 | from operator import methodcaller |
Freezing arguments with functools.partial
functools.partial is a higher-roder function that allows partial application of a function. Given a function, a partial application produces a new callable with some of the arguments of the original function fixed.
1 | from operator import mul |