forked from octallium/modern-python-101
-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathhof.py
135 lines (88 loc) · 3.22 KB
/
hof.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
"""
Higher Order Functions:
-----------------------
Please note that this is a advanced topic, so it may take a couple of attempts
to understand these concepts.
Functions under the hood are just `Objects`, they can be passed to other
functions and functions can also return functions!
This data type is called as `Callable`, one which can be called or invoked.
Note:
-----
Till now we have been sending data to our functions, but sending data every time
can be expensive, instead we can send function to data!
Don't spend too much time mastering this topic, it will come naturally as you
progress with your programming skills.
"""
# -------------------------------------------------------------------------
from typing import Callable
def hello() -> None:
"""Prints Hello World"""
print("Hello World!")
# hello is just a regular object or class of type `function`
print(hello)
print(type(hello))
print(id(hello))
# We can assign function to variables
greet: Callable[[], None] = hello # just assigns the object `hello` to greet variable
greet() # we can invoke/call the function using `()` at the end
# -------------------------------------------------------------------------
"""
Let's try to create a universal greeter that can greet a person in multiple
ways.
"""
def zola(name: str) -> str:
return f"Zola, {name}!"
def good_morning(name: str) -> str:
return f"Good Morning, {name}!"
def goodbye(name: str) -> str:
return f"Goodbye, {name}!"
# Function accepting a function
def universal_greeter(name: str, greeter: Callable[[str], str]) -> None:
"""Can greet in multiple ways"""
msg = greeter(name)
print(msg)
universal_greeter("Louis", zola)
universal_greeter("Louis", good_morning)
universal_greeter("Louis", goodbye)
# -------------------------------------------------------------------------
"""
Functions returning functions!!
------------------------------
This can be confusing, relax if you can't get it, it took me several attempts
to understand this!
"""
# Function returning a function
def add_by_5(num: int) -> Callable[[], int]:
"""Add by 5"""
def by_5() -> int:
return num + 5
return by_5
sum = add_by_5(5)
print(sum())
# Function returning a function
def unique_adder(num1: int) -> Callable[[int], int]:
"""Adds two numbers and then subtracts by 1"""
def adder(num2: int) -> int:
return num1 + num2 - 1
return adder
addr = unique_adder(5)
print(addr(5))
# -------------------------------------------------------------------------
"""
Lambda:
-------
Perhaps the most neglected, but very powerful technique to work with functions.
Again, don't spend too much time mastering it, it will come naturally!
The way in which we declared functions are very verbose, we can condense them
in a single statement.
Let's try to create a calculator from scratch
"""
add: Callable[[int, int], int] = lambda x, y: x + y
subtract: Callable[[int, int], int] = lambda x, y: x - y
multiply: Callable[[int, int], int] = lambda x, y: x * y
def calc(num1: int, num2: int, operation: Callable[[int, int], int]) -> int:
"""Performs the maths operation on the numbers"""
return operation(num1, num2)
print(calc(4, 5, add))
print(calc(4, 5, subtract))
print(calc(4, 5, multiply))