23 Oct 2020 |
python
decorators
functional
We saw what higher order functions are and how they can be used in creating partially applied functions in previous posts. Now let us see how we can use higher order functions to implement python decorators.
Let us say you want to intercept your function call to log the arguments passed and the return value. ie.
def add(a, b):
return a + b
add(2, 3)
# When called with 2 and 3 as arguments, it should print
> Function add called with arguments: 2, 3
> Function add returned: 5
It is quite easy to do this. Let us start with defining a function log
.
def log(fun):
def inner(*args, **kwargs):
print(
f"Function {fun.__name__} "
f"called with arguments: {*args, *kwargs}")
ret_value = fun(*args, **kwargs)
print(f"Function {fun.__name__} returned: {ret_value}")
return ret_value
return inner
add_with_logging = log(add)
add_with_logging(1, 2)
# Prints the following
> Function add called with arguments: (1, 2)
> Function add returned: 3
But this isn’t good. You are creating a new function and have to replace all usages of add
with add_with_logging
. There is an easy fix.
# Redefine the name add to log(add)
add = log(add)
add(1, 2)
# Prints the following
> Function add called with arguments: (1, 2)
> Function add returned: 3
This is called a decorator pattern and is quite widely used in python. Python provides some syntactic sugar for this usage. All you need to do is add @log
before the function definition.
@log
def add(a, b):
return a + b
add(1, 2)
# Prints the following
> Function add called with arguments: (1, 2)
> Function add returned: 3
22 Oct 2020 |
python
functional
In the previous post, we discussed higher order functions. Ones that take functions as arguments and ones that return functions as arguments. Now let us look at some that do both.
In languages like haskell, there is a feature called Currying. When a function which takes multiple arguments is called with less than the number of expected arguments, it returns another function with the arguments “partially applied”. For Eg:-
-- Define a function
add a b = a + b
-- Call the function.
-- There are no braces for function calls in haskell
add 1 2 -- Returns 3
-- Below even though add is a 2 argument function,
-- we can pass a single argument and "partially apply" the argument
addTen = add 10
-- addTen is a function
addTen 32 -- Returns 42
Now, let us try and get this behavior in python. Mind you, we can’t get so nice a syntax with our python implementation. What can we expect?
# define our add function
def add(a, b):
return a + b
To partially apply a single argument, let us define a function that can be used as follows:
addTen = partial(add, 10)
partial
should be a function that returns a closure which has access to the function and the argument passed to it.
def partial(fun, arg1):
def inner(*args):
return fun(arg1, *args)
return inner
addTen = partial(add, 10)
addTen(32) # Returns 42
A better production ready version for partial
is available in the functools
library of python. You can access it by from functools import partial
Partial can be applied to functions which has more than 2 arguments as well.
def add3(a, b, c):
return a + b + c
addTen = partial(partial(add3, 4), 6)
addTen(32) # Returns 42
21 Oct 2020 |
python
functional
My first encounter with a higher order function was when I ran man qsort
and noticed its type.
void qsort(void *base, size_t nmemb, size_t size,
int (*compar)(const void *, const void *));
For someone who had only seen primitive types like int
and long
and char
, int (*compar)(const void *, const void *)
was quite the surprise.
I later found out that it was the type for a function which took two arguments and returned an int
. Complicated looking syntax aside, this is quite interesting. Passing a function allows you to create a generic qsort
function which can be use to sort anything with a custom sorting logic.
A higher order function is a function that takes other functions as arguments or return functions.
When I picked up python a few years later, higher order functions were everywhere. And pretty easy to use.
# Let us define a function that prints "Hello world"
def hello():
print("Hello world")
# call is a higher order function which just calls a function passed to it without arguments
def call(fun):
fun()
# Look ma! I passed a function
call(hello) # prints Hello world
Now, what if you want to make a function which can call functions which takes arguments. This is were python’s *args
and **kwargs
come into picture. Let us redefine our call
function.
# add takes two numbers and return the sum
def add(a, b):
return a+b
def call(fun, *args, **kwargs):
return fun(*args, **kwargs)
# Call add with positional arguments
call(add, 1, 2) # returns 3
# Call add with named arguments
call(add, a=1, b=2) # returns 3
Functions in python can return other functions too
def make_hello():
def say_hello():
print("Hello world")
return say_hello
# Call make_hello and assign the return function to a variable.
# Then use it like any normal function
hello = make_hello()
hello()
Now, let us do something fun with this
def make_adder(n):
def adder(m):
return m + n
return adder
add_one = make_adder(1)
add_one(10) # returns 11
add_42 = make_adder(42)
add_42(10) # returns 52
Here, we return a function adder
from inside make_adder
. Notice how the inner function has access to the variable n
even after the execution of make_adder
is complete. This inner function along with its scope is called a closure.
Languages like python
, javascript
, dart
etc supports closures.
20 Oct 2020 |
vim
Vim has multiple modes. You normally insert text in the Insert
mode. Normal
mode is where you move around and give commands to vim.
Esc
will take you to normal mode(usually). You can enter a command starting with a :
. Quit vim with the below command:
q
- quit
a
- all
!
- force do the operation.
This will quit all the buffers including the unsaved ones.