AkulMehra
Akul Mehra
def func():
pass
def hello():
''' Basic example of function. '''
return 'Hello World'
print(hello())
# Output: Hello World
def add(a, b):
''' take a and b as args, add them and
return the result. '''
return a + b
print(add(2,5))
# Output: 7
As an object, you can assign the function to a variable
def hello():
print 'Hello'
hello()
# prints 'Hello'
hi = hello
hi()
# prints 'Hello'
They can be passed around like other values (strings, integers, objects, etc.).
def add(a, b):
return a + b
def apply(func, x, y):
return func(x, y)
print apply(add, 2, 5)
# outputs: 7
Function can be defined inside another function. That means a function can return another function.
def print_me(word):
def inner():
print(word)
return inner
f = print_me('Hello World!')
f()
# prints 'Hello World!'
This is called a closure
def my_decorator(original_function):
def new_function(*args, **kwargs):
print 'Entering', original_function.__name__
result = original_function(*args, **kwargs)
print 'Exiting', original_function.__name__
return result
return new_function
@my_decorator
def my_func():
pass
# Syntactic Sugar
@my_decorator
def my_func():
pass
Under the hood
is same as writing:
def my_func():
pass
my_func = my_decorator(my_func)
*args and **kwargs enable the function to accept any number of postional and keyword arguments.
*args is a list
**kwargs is a dictionary
*args & **kwargs
*args becomes args[0], args[1], args[2] ...
**kwargs becomes key1=kwargs[key1], key2=kwargs[key2] ...
*args & **kwargs
import time
def timeit(func):
def inner(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
time_taken = time.time() - start_time
print('Time taken is ', time_taken)
return result
return inner
@timeit
def sleep(t=1):
print('sleeping for ', t)
time.sleep(t)
sleep()
# sleeping for 1
# Time taken is 1.005326747894287
sleep(2)
# sleeping for 2
# Time taken is 2.004933118820190
Examples
import time
def memo(func):
''' Decreases the time taken by func from
exponential to linear time. '''
cache = {}
def inner(*args):
if args in cache:
return cache[args]
else:
result = func(*args)
cache[args] = result
return result
return inner
@memo
def fibo(n):
if n < 2:
return n
return fibo(n - 1) + fibo(n - 2)
start_time = time.time()
print(fibo(40))
print('Time taken: ', time.time() - start_time)
# Without memoization: Time taken is 54.21900486946106s
# With memoization: Time taken is 0.00011396408081054688s
Examples
def count(func):
def inner(*args, **kwargs):
inner.counter += 1
return func(*args, **kwargs)
inner.counter = 0
return inner
@count
def myfunc():
pass
Examples
In [1]: from counter import *
In [2]: myfunc()
In [3]: myfunc()
In [4]: myfunc()
In [5]: myfunc.counter
Out[5]: 3
def polynomial_creator(a, b, c):
def polynomial(x):
return a * x**2 + b * x + c
return polynomial
p1 = polynomial_creator(2, 3, -1)
x = 2
print('x: ', x, 'p(x): ', p1(x))
# Output:
# x: 2, p(x): 13
# 2 * 2**2 + 3 * 2 + (-1) = 13
Examples
POLYNOMIAL FUNCTIONS
def makebold(fn):
def wrapped():
return "<b>" + fn() + "</b>"
return wrapped
def makeitalic(fn):
def wrapped():
return "<i>" + fn() + "</i>"
return wrapped
@makebold
@makeitalic
def hello():
return "hello world"
print(hello()) ## Outputs: "<b><i>hello world</i></b>"
@makebold
@makeitalic
def hello():
return "hello world"
def hello():
return "hello world"
hello = makebold(makeitalic(hello))
The above syntactic sugar statement is same as:
def shout(func):
def inner(*args, **kwargs):
''' Inner func modifies the behaviour of original func '''
print('BEFORE SHOUTING')
result = func(*args, **kwargs)
print('AFTER SHOUTING')
return result
return inner
@shout
def hello(name='World'):
''' returns hello with name argument '''
print('Hello', name)
hello('HDE Team')
# Output
BEFORE SHOUTING
Hello HDE Team
AFTER SHOUTING
In [1]: from shout import *
BEFORE SHOUTING
Hello HDE Team
AFTER SHOUTING
In [2]: hello.__name__
Out[2]: 'inner'
In [3]: hello.__doc__
Out[3]: ' Inner func modifies the behavior of original func '
Using decorators override the metadata of the original function.
Using decorators override the metadata of the original function.
Using functools.wraps copies the metadata like name and docstring of the original function inside the decorator function
from functools import wraps
def shout(func):
@wraps(func)
def inner(*args, **kwargs):
''' Inner func modifies the behaviour of original func '''
print('BEFORE SHOUTING')
result = func(*args, **kwargs)
print('AFTER SHOUTING')
return result
return inner
@shout
def hello(name='World'):
''' returns hello with name argument '''
print('Hello', name)
hello('HDE Team')
Using wraps from functools library
Using wraps from functools library
In [1]: from shout import *
BEFORE SHOUTING
Hello HDE Team
AFTER SHOUTING
In [2]: hello.__name__
Out[2]: 'hello'
In [3]: hello.__doc__
Out[3]: ' returns hello with name argument '
def skipIf(condition, message):
def dec(func):
def inner(*args, **kwargs):
if not condition:
return func(*args, **kwargs)
else: # skip the func
print(message)
return inner
return dec
@skipIf(False, 'Do not skip this')
def enter():
print('In the Enter function')
@skipIf(True, 'Skipped this function')
def exit():
print('In the Exit function')
enter()
exit()
# Output
In the Enter function
Skipped this function
@skipIf(False, 'Do not skip this')
def enter():
print('In the Enter function')
enter()
def enter():
print('In the Enter function')
enter = skipIf(False, 'Do not skip this')(enter)
is same as below statement
skipIf creates a decorator named dec and returns it, which is called with enter function as an argument
def make(word):
def dec(fn):
def wrapped():
return "<" + word + ">" + fn() + "</" + word + ">"
return wrapped
return dec
@make('b') # To make bold
@make('i') # To make italic
def hello():
return "hello world"
print(hello()) # Outputs: "<b><i>hello world</i></b>"
Make Generic ( Bold & Italic ) Decorators
Text
def decorate(func):
''' decorate functions '''
def inner(*args, **kwargs):
print('*' * 20)
result = func(*args, **kwargs)
print('*' * 20)
return result
return inner
def decorate_class(cls):
'''
Takes class object as input and apply decorate
func to all the callable functions.
'''
for k, v in vars(cls).items():
if callable(v):
setattr(cls, k, decorate(v))
return cls
@decorate_class
class Area:
'''
Functions to calculate area.
'''
def triangle(self, b, h):
print('Area of right triangle: ', 0.5 * b * h)
def square(self, s):
print('Area of square: ', s * s)
def rectangle(self, l, b):
print('Area of rectangle: ', l * b)
In [1]: from decorate_class import *
In [2]: ar = Area()
In [3]: ar.triangle(10, 15)
********************
Area of right triangle: 75.0
********************
In [4]: ar.square(10)
********************
Area of square: 100
********************
In [5]: ar.rectangle(10,15)
********************
Area of rectangle: 150
********************
Output
class App:
route_functions = {}
def route(url_pattern):
def wrap(f):
route_functions[url_pattern] = f
return f
return wrap
@app.route decorator
@app.route(“/”)
def index():
return “Hello world”
index = app.route(“/”)(index) = wrap(index) = index
# index is added to the route_functions mapping with url pattern.
route_functions['/'] = index
def login_required(f):
def wrap(*args, **kwargs):
# if user is not logged in, redirect to login page
if not request.headers["authorization"]:
return redirect("login page")
# get user via some ORM system
user = User.get(request.headers["authorization"])
# make user available down the pipeline via flask.g
g.user = user
# finally call f. f() now haves access to g.user
return f(*args, **kwargs)
return wrap
@login_required decorator
@app.route(“/”)
@login_required
def index():
return “Hello world”
AkulMehra
akul08
akul08
AkulMehra
akul08
akul08