Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit c3b5057

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

2 files changed

Lines changed: 92 additions & 0 deletions

File tree

‎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)

AltStyle によって変換されたページ (->オリジナル) /