Lecture Notes 17#

@pytest.mark.parametrize
def test_xxx():
    ...
def f(x):
    return x**2
def g(func):
    print("Calling function with x=2")
    result = func(2)
    print("Return value", result)
    return result
g(f)
Calling function with x=2
Return value 4
4
  • function that takes another function as input

decorators#

  • function that take a function as input and returns a function as output

def id_decorator(func):
    return func
g = id_decorator(f)
g(2)
4
f(2)
4
  • decorator that reports timing

import time
def f(x):
    time.sleep(1)
    return x**2
f(2)
4
t1 = time.time()
f(2)
t2 = time.time()
print("Time used in function", t2-t1)
Time used in function 1.0004487037658691
def time_me(func):
    def wrapper(x):
        t1 = time.time()
        result = func(x)
        t2 = time.time()
        print("Time used in function", t2-t1)
        return result
    return wrapper
time_me(f)(2)
Time used in function 1.0001564025878906
4
f = time_me(f)
f(2)
Time used in function 1.00007963180542
4
@time_me
def f(x, a=1):
    time.sleep(1)
    return a*x**2
f(2)
Time used in function 1.0001444816589355
4
f(2, a=.1)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[17], line 1
----> 1 f(2, a=.1)

TypeError: time_me.<locals>.wrapper() got an unexpected keyword argument 'a'

For general arguments: args/kwargs

def wrapper(*args, **kwargs):
    print(args)
    print(kwargs)
wrapper()
()
{}
wrapper(1, 2)
(1, 2)
{}
wrapper(1, 2, c=3)
(1, 2)
{'c': 3}
def time_me(func):
    def wrapper(*args, **kwargs):
        t1 = time.time()
        result = func(*args, **kwargs)
        t2 = time.time()
        print("Time used in function", t2-t1)
        return result
    return wrapper
@time_me
def f(x, a=1):
    time.sleep(1)
    return a*x**2
f(2)
Time used in function 1.0001630783081055
4
f(2, a=0.1)
Time used in function 1.0001263618469238
0.4
  • decorator for debugging

def trace(func):
    def wrapper(*args, **kwargs):
        print(f"{func.__name__} called with arguments {args}, {kwargs}")
        result = func(*args, **kwargs)
        print(f"{func.__name__} returns {result}")
        return result
    return wrapper

def time_me(func):
    def wrapper(*args, **kwargs):
        t1 = time.time()
        result = func(*args, **kwargs)
        t2 = time.time()
        print(f"Time used in {func.__name__}", t2-t1)
        return result
    return wrapper
@time_me
@trace
def my_square(x, a=1):
    time.sleep(1)
    return a*x**2
my_square(2, a=0.1)
my_square called with arguments (2,), {'a': 0.1}
my_square returns 0.4
Time used in wrapper 1.000516653060913
0.4
from functools import wraps

def trace(func):
    
    @wraps(func)
    def wrapper(*args, **kwargs):
        print(f"{func.__name__} called with arguments {args}, {kwargs}")
        result = func(*args, **kwargs)
        print(f"{func.__name__} returns {result}")
        return result
    return wrapper

def time_me(func):
    
    @wraps(func)
    def wrapper(*args, **kwargs):
        t1 = time.time()
        result = func(*args, **kwargs)
        t2 = time.time()
        print(f"Time used in {func.__name__}", t2-t1)
        return result
    return wrapper
@time_me
@trace
def my_square(x, a=1):
    time.sleep(1)
    return a*x**2
my_square(2, a=0.1)
my_square called with arguments (2,), {'a': 0.1}
my_square returns 0.4
Time used in my_square 1.0028369426727295
0.4
import functools

@functools.cache
@time_me
def my_square(x, a=1):
    time.sleep(1)
    return a*x**2
my_square(3, a=.1)
Time used in my_square 1.000098466873169
0.9
my_square(4, a=1)
Time used in my_square 1.0000760555267334
16
my_square(3, a=.1)
0.9
my_square(4, a=1)
16
my_square(4, a=2)
Time used in my_square 1.0001099109649658
32