Module 2: Functional programming II Flashcards
Decorators, Currying, Partial, Closures
What are useful applications of higher-order functions?
- Function composition
- Decorators
- Currying
- Partial
- Closures
What are Decorators?
Decorators take an existing function and add some functionality (or “decoration”) over it
What is this code exemplifying?
def make_polite(func):
def inner():
print(“Hello, world! “,)
func()
return inner
@make_polite
def another_function():
print(“I am some other ordinary
function.”)
Decorator
The code is an example of a DECORATOR because it wraps another function (another_function
) to modify its behavior without changing its code. The make_polite
function adds a greeting before the original function’s output. Using @make_polite
applies this modification, demonstrating a decorator’s purpose: to extend or alter a function’s behavior dynamically.
When you apply @make_polite to another_function, another_function gets wrapped by inner. Therefore, calling another_function() now actually calls inner(), which in turn does two things:
Prints “Hello, world!”
Calls the original another_function() content, printing “I am some other ordinary function.”
Does a decorator modify the internal code of a function?
No, decorators add functionality but DON”T change the internal code of a functions thanks to function composition.
new function = decorator (original_function)
Original function is not changed and we keep the same interface.
Why are decorators useful?
Useful to maintain and augment existing code that is already working!
What are the phases when using decorators? Explain.
- Wrap: at definition time, the decorator takes the original function and returns
a new wrapped function - Evaluate: at evaluation time, the wrapping function usually calls the original
function. The wrapping function can pre-process the argument values or
post-process the return value (or both)
What are some common scenarios in which decorators are useful?
- Logging
- Security
- Handling incomplete data
How could you rewrite this multi-argument function?
f(a,b,c) = x
h = g(a)
i = h(b)
j = i(c) = x
or more compactly:
g(a)(b)(c)
What is currying?
The process of turning multi-argument functions into a composition of single argument functions
What is the natural way to implement currying?
Using decorators to add curry to the function
What does currying allow us to do?
- Look at the intermediate steps of a function
- Create specialized functions
What does currying rely on?
Function composition
Why is currying interesting from a functional programming perspective?
- by separating one complex multi-argument function into single argument functions,
we have simpler components: functions only have one input and one output - functions are compatible with theoretical frameworks that only allow single argument
functions (e.g. lambda calculus)
What does Partial do?
With partial, we can call multi-argument functions with less arguments than they require, and obtain a specialized function with fixed arguments.
What does Partial return?
Partial may return a (possibly multi-argument) function, or value
What is the difference between currying and partial
Currying: Focus to create and return a single argument.
Partial: Can return a multi-argument function.
Explain this code:
from functools import partial
def operation(x, y, z):
return x * (y + z)
doublesum = partial(operation, 2)
doublesum(3,1)
doublesum is now a more specialized function that always multiplies by 2.
Return 8
What are Closures?
Closure is a function that remembers values
What does this code show?
def outer_func():
pi = 3.14
def inner_func():
print(f”pi is : {pi}”)
return inner_func
f=outer_func()
f()
The outer_func function prints “pi is 3.14”
The pi variable is a nonlocal variable for the inner_func function.
This is closure!!
This code demonstrates the concept of closures in Python. A closure occurs when a nested function (here, inner_func) references a value in its enclosing scope (here, pi from outer_func), and Python allows the nested function to access that value even after the outer function has finished execution.
Why are closures useful?
To avoid the use of global.
What is Decorating?
- Wrapping a function to add some “decoration” (extra functionality) to it.
- Is is a form of composition.
What is Currying?
- Procedure to convert a multi-argument function into a chain of single-argument functions
- The intermediate functions may be accessed for creation of specialized functions
- It relats to lambda calculus
What are Partials?
- Runs a function with less arguments than declared in its signature
- Main application is the creation of specialized functions (i.e. functions tied to some values)
- Often mixed with currying
What is a Closure?
A closure is a function that remembers and can access variables from the scope where it was created, even after that scope has finished executing.
What design patterns can be used to create specialized functions?
- Currying
- Partial
- Closure