Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit c3b5057

Browse files
committed
Add section about function decorators.
1 parent 9388654 commit c3b5057

File tree

2 files changed

+92
-0
lines changed

2 files changed

+92
-0
lines changed

‎README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ written correctly.
9292
- [Lambda Expressions](src/functions/test_lambda_expressions.py) (`lambda` statement)
9393
- [Documentation Strings](src/functions/test_function_documentation_string.py)
9494
- [Function Annotations](src/functions/test_function_annotations.py)
95+
- [Function Decorators](src/functions/test_function_decorators.py)
9596
6. **Classes**
9697
- [Class Definition](src/classes/test_class_definition.py) (`class` statement)
9798
- [Class Objects](src/classes/test_class_objects.py)
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
"""Function Decorators.
2+
3+
@see: https://www.thecodeship.com/patterns/guide-to-python-function-decorators/
4+
5+
Function decorators are simply wrappers to existing functions. In the context of design patterns,
6+
decorators dynamically alter the functionality of a function, method or class without having to
7+
directly use subclasses. This is ideal when you need to extend the functionality of functions that
8+
you don't want to modify. We can implement the decorator pattern anywhere, but Python facilitates
9+
the implementation by providing much more expressive features and syntax for that.
10+
"""
11+
12+
13+
def test_function_decorators():
14+
"""Function Decorators."""
15+
16+
# Function decorators are simply wrappers to existing functions. Putting the ideas mentioned
17+
# above together, we can build a decorator. In this example let's consider a function that
18+
# wraps the string output of another function by p tags.
19+
20+
# This is the function that we цфте to decorate.
21+
def greeting(name):
22+
return "Hello, {0}!".format(name)
23+
24+
# This function decorates another functions output with <p> tag.
25+
def decorate_with_p(func):
26+
def function_wrapper(name):
27+
return "<p>{0}</p>".format(func(name))
28+
return function_wrapper
29+
30+
# Now, let's call our decorator and pass the function we want decorate to it.
31+
my_get_text = decorate_with_p(greeting)
32+
33+
# Here we go, we've just decorated the function output without changing the function itself.
34+
assert my_get_text('John') == '<p>Hello, John!</p>' # With decorator.
35+
assert greeting('John') == 'Hello, John!' # Without decorator.
36+
37+
# Now, Python makes creating and using decorators a bit cleaner and nicer for the programmer
38+
# through some syntactic sugar There is a neat shortcut for that, which is to mention the
39+
# name of the decorating function before the function to be decorated. The name of the
40+
# decorator should be prepended with an @ symbol.
41+
42+
@decorate_with_p
43+
def greeting_with_p(name):
44+
return "Hello, {0}!".format(name)
45+
46+
assert greeting_with_p('John') == '<p>Hello, John!</p>'
47+
48+
# Now let's consider we wanted to decorate our greeting function by one more functions to wrap a
49+
# div the string output.
50+
51+
# This will be our second decorator.
52+
def decorate_with_div(func):
53+
def function_wrapper(text):
54+
return "<div>{0}</div>".format(func(text))
55+
return function_wrapper
56+
57+
# With the basic approach, decorating get_text would be along the lines of
58+
# greeting_with_div_p = decorate_with_div(decorate_with_p(greeting_with_p))
59+
60+
# With Python's decorator syntax, same thing can be achieved with much more expressive power.
61+
@decorate_with_div
62+
@decorate_with_p
63+
def greeting_with_div_p(name):
64+
return "Hello, {0}!".format(name)
65+
66+
assert greeting_with_div_p('John') == '<div><p>Hello, John!</p></div>'
67+
68+
# One important thing to notice here is that the order of setting our decorators matters.
69+
# If the order was different in the example above, the output would have been different.
70+
71+
# Passing arguments to decorators.
72+
73+
# Looking back at the example before, you can notice how redundant the decorators in the
74+
# example are. 2 decorators(decorate_with_div, decorate_with_p) each with the same
75+
# functionality but wrapping the string with different tags. We can definitely do much better
76+
# than that. Why not have a more general implementation for one that takes the tag to wrap
77+
# with as a string? Yes please!
78+
79+
def tags(tag_name):
80+
def tags_decorator(func):
81+
def func_wrapper(name):
82+
return "<{0}>{1}</{0}>".format(tag_name, func(name))
83+
return func_wrapper
84+
return tags_decorator
85+
86+
@tags('div')
87+
@tags('p')
88+
def greeting_with_tags(name):
89+
return "Hello, {0}!".format(name)
90+
91+
assert greeting_with_tags('John') == '<div><p>Hello, John!</p></div>'

0 commit comments

Comments
 (0)