9.6 KiB
9.6 KiB
First-Class and Higher-Order Functions¶
In [1]:
def add_numbers(x, y): return x + y my_function = add_numbers my_function(3, 4)
Out[1]:
7
In [2]:
# Example mode = "PROD" def load_data_real(): print("loading data from a third-party API ...") return [100, 200, 300] def load_data_test(): return [1, 2, 3] load_data = load_data_real if mode == "PROD" else load_data_fake load_data() # rest of code can use this function....
loading data from a third-party API ...
Out[2]:
[100, 200, 300]
Passing functions as an argument¶
In [3]:
def subtract_numbers(x, y): return x - y def combine_numbers(x, y, func): return func(x, y) print(combine_numbers(10, 20, subtract_numbers)) print(combine_numbers(10, 20, add_numbers))
-10 30
Return functions¶
In [20]:
def create_printer(arg): # arg is a use of closure def say_hello(): print(f"hello from inside an other function {arg}") return say_hello printer_1 = create_printer("ARG") printer_1() printer_2 = create_printer("XXXXXX") printer_2()
hello from inside an other function ARG hello from inside an other function XXXXXX
Examples Higher order functions¶
In [31]:
def create_sales_calculator(percentage_discount): def calculator(price): return price * (1 - percentage_discount) return calculator discount = 0.20 price = 220 final_price = create_sales_calculator(discount)(price) print(final_price)
176.0
In [23]:
def create_spy(function_name): def inner(func): def spy_func(arg): print(f"The {function_name} was called") return func(arg) return spy_func return inner @create_spy("Double") def double(x): return x * 2 @create_spy("Square") def square(x): return x * x @create_spy("Greet") def greet(name): print(f"Hello {name}") # double(square(10)) # greet('Paul') double(9)
The Double was called
Out[23]:
18
test performance of a function; find bottlenecks¶
In [24]:
import datetime def add_performance_watch(func): def inner(*args, **kwargs): start = datetime.datetime.now() result = func(*args, **kwargs) print((kwargs)) end = datetime.datetime.now() total_time = end - start print(f"The {func.__name__} functions executed in {total_time}") return result return inner @add_performance_watch @create_spy("Double") def double(x): return x * 2 @add_performance_watch @create_spy("Square") def square(x): return x * x @add_performance_watch @create_spy("Greet") def greet(name): print(f"Hello {name}") double(square(9))
The Square was called {} The spy_func functions executed in 0:00:00.000023 The Double was called {} The spy_func functions executed in 0:00:00.000005
Out[24]:
162
Isomorphic funtions¶
In [35]:
def list_or_value(func): def wrapper(arg): if isinstance(arg, list): return list(map(func, arg)) else: return func(arg) return wrapper @list_or_value def double(x): return x * 2 @list_or_value def minus_one(x): return x - 1 numbers = list(range(1, 6)) print(double(9)) print(minus_one(9)) print(double(numbers)) print(minus_one(numbers))
18 8 [2, 4, 6, 8, 10] [0, 1, 2, 3, 4]
Function tracking¶
In [45]:
import datetime def print_stats(func): def wrapper(*args, **kwargs): start = datetime.datetime.now() result = func(*args, **kwargs) end = datetime.datetime.now() total_time = end - start stats = { "name": func.__name__, "args": args, "kwargs": kwargs, "result": result, "total_time": total_time, } print(stats) return wrapper @print_stats def double(x): return x * 2 @print_stats def add(x, y, z): return x + y + z @print_stats def greet(x): return x double(9) add(1, 2, z=9) greet(("Hello"))
{'name': 'double', 'args': (9,), 'kwargs': {}, 'result': 18, 'total_time': datetime.timedelta(microseconds=3)} {'name': 'add', 'args': (1, 2), 'kwargs': {'z': 9}, 'result': 12, 'total_time': datetime.timedelta(microseconds=2)} {'name': 'greet', 'args': ('Hello',), 'kwargs': {}, 'result': 'Hello', 'total_time': datetime.timedelta(microseconds=2)}
Argument checking¶
In [ ]: