Skip to content

Commit dbadc24

Browse files
committed
📝 Added 31-decorators.md
1 parent 8e64617 commit dbadc24

File tree

1 file changed

+272
-0
lines changed

1 file changed

+272
-0
lines changed

31-decorators.md

+272
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,272 @@
1+
# Python Decorators
2+
3+
**Video link:** [https://youtu.be/8hWIWyBfdQE](https://youtu.be/8hWIWyBfdQE)
4+
5+
In this video, we learned how to create decorators and why we should use them.
6+
7+
**Programs in the Video**
8+
9+
- [Prerequisites for Decorators](#prerequisites-for-decorators)
10+
- [Python Decorators](#python-decorators-1)
11+
- [Decorating Functions with Parameters](#decorating-functions-with-parameters)
12+
- [Chaining Decorators in Python](#chaining-decorators-in-python)
13+
14+
---
15+
16+
## Prerequisites for Decorators
17+
Before we learn about decorators, we must first understand a few basic things in Python.
18+
19+
**We must be comfortable with the fact that everything in Python is an object, including classes as well as functions**.
20+
Variables are simply identifiers bound to these objects.
21+
22+
Since functions are also objects, we can also pass functions as arguments to other functions:
23+
24+
```python
25+
def inc(x):
26+
return x + 1
27+
28+
def operate(func, x):
29+
result = func(x)
30+
return result
31+
32+
print(operate(inc, 3))
33+
```
34+
35+
**Output**
36+
```
37+
4
38+
```
39+
40+
**In Python, we can also define a function inside a function**:
41+
42+
```python
43+
def print_msg(message):
44+
greeting = "Hello"
45+
def printer():
46+
print(greeting, message)
47+
48+
printer()
49+
50+
51+
print_msg("Python is awesome")
52+
```
53+
54+
**Output**
55+
56+
```
57+
Hello Python is awesome
58+
```
59+
60+
**Functions is that they can also return a function as a value.** Let's modify our previous code:
61+
62+
```python
63+
def print_msg(message):
64+
greeting = "Hello"
65+
def printer():
66+
print(greeting, message)
67+
68+
return printer
69+
70+
func = print_msg("Python is awesome")
71+
func()
72+
```
73+
74+
**Output**
75+
```
76+
Hello Python is awesome
77+
```
78+
79+
Do you notice something weird here? Even though `print_msg()` function is done executing, the returned inner `printer()` function
80+
can still access the `message` and `greeting` variables. Such a function is called a closure function.
81+
82+
A closure is simply an inner function that remembers the values and variables in its enclosing scope even if the outer function is done executing.
83+
84+
Python Decorators make an extensive use of closures.
85+
86+
---
87+
88+
## Python Decorators
89+
90+
A Python decorator is a function that takes in a function, adds some functionality to it and returns the original function.
91+
92+
Let's try to build a decorator function that prints out some information before and after executing another function.
93+
94+
```python
95+
def printer():
96+
print("Hello, World!")
97+
98+
99+
def display_info(func):
100+
def inner():
101+
print("Executing",func.__name__,"function")
102+
func()
103+
print("Finished execution")
104+
return inner
105+
```
106+
107+
Let's call `printer()` normally first.
108+
109+
110+
```python
111+
def printer():
112+
print("Hello, World!")
113+
114+
115+
def display_info(func):
116+
def inner():
117+
print("Executing",func.__name__,"function")
118+
func()
119+
print("Finished execution")
120+
return inner
121+
122+
printer()
123+
```
124+
125+
**Output**
126+
127+
```
128+
Hello, World!
129+
```
130+
131+
Now, let's use the decorator function to run the same `printer` function.
132+
133+
```python
134+
def printer():
135+
print("Hello, World!")
136+
137+
138+
def display_info(func):
139+
def inner():
140+
print("Executing",func.__name__,"function")
141+
func()
142+
print("Finished execution")
143+
return inner
144+
145+
decorated_func = display_info(printer)
146+
decorated_func()
147+
```
148+
149+
**Output**
150+
151+
```
152+
Executing printer function
153+
Hello, World!
154+
Finished execution
155+
```
156+
157+
In python, we have a much more elegant way of to achieve this functionality using the `@` symbol.
158+
159+
160+
```python
161+
def display_info(func):
162+
def inner():
163+
print("Executing",func.__name__,"function")
164+
func()
165+
print("Finished execution")
166+
return inner
167+
168+
@display_info
169+
def printer():
170+
print("Hello, World!")
171+
172+
printer()
173+
```
174+
175+
**Output**
176+
```
177+
Executing printer function
178+
Hello, World!
179+
Finished execution
180+
```
181+
182+
---
183+
184+
## Decorating Functions with Parameters
185+
186+
Suppose we have a simple `divide` function.
187+
188+
```python
189+
def divide(a, b):
190+
return a/b
191+
```
192+
193+
We know this code will throw an exception if we pass the value for `b` as `0`.
194+
195+
Let's make a decorator function called `smart_divide` to prevent this.
196+
197+
```python
198+
def smart_divide(func):
199+
def inner(a, b):
200+
print("Dividing", a, "by", b)
201+
if b == 0:
202+
print("Cannot divide by 0!")
203+
return
204+
205+
return func(a, b)
206+
return inner
207+
208+
209+
@smart_divide
210+
def divide(a, b):
211+
return a/b
212+
213+
value1 = divide(15, 3)
214+
print(value1)
215+
216+
value2 = divide(5, 0)
217+
print(value2)
218+
```
219+
220+
**Output**
221+
222+
```
223+
Dividing 15 by 3
224+
5.0
225+
Dividing 5 by 0
226+
Cannot divide by 0!
227+
None
228+
```
229+
230+
---
231+
232+
## Chaining Decorators in Python
233+
234+
In Python, a function can be decorated multiple times with different or the same decorator.
235+
236+
Here, are two decorator functions called `star` and `percent`. These functions print a series of star and percentage symbols before and after executing the function
237+
238+
```python
239+
def star(func):
240+
def inner(arg):
241+
print("*" * 30)
242+
func(arg)
243+
print("*" * 30)
244+
return inner
245+
246+
def percent(func):
247+
def inner(arg):
248+
print("%" * 30)
249+
func(arg)
250+
print("%" * 30)
251+
return inner
252+
253+
@star
254+
@percent
255+
def printer(msg):
256+
print(msg)
257+
258+
printer("Decorators are wonderful")
259+
```
260+
261+
**Output**
262+
```
263+
******************************
264+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
265+
Decorators are wonderful
266+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
267+
******************************
268+
```
269+
270+
As you can see, these decorators are chained and they wrap the original function.
271+
272+
Here, we have first called the `star` function, and then the `percent` function. So the `star` function wraps the `percent` function which in turn wraps the `printer` function.

0 commit comments

Comments
 (0)