"Decoration is a way to specify management code for functions and classes." ... "A decorator itself is a callable that returns a callable." - Mark Lutz
A function object is a callable. So, the previous statement can be translated into:
A decorator is a function that takes a function object as its argument, and returns a function object, and in the process, makes necessary modifications to the input function, possibly enhancing it. - Bogotobogo
"Indeed, you can use Python decorators to implement the Decorator pattern, but that's an extremely limited use of it. Python decorators, I think, are best equated to macros....
... I think it's safe to say that the goal of macros in a language is to provide a way to modify elements of the language. That's what decorators do in Python -- they modify functions, and in the case of class decorators, entire classes. This is why they usually provide a simpler alternative to metaclasses." - Bruce Eckel in Decorators I: Introduction to Python Decorators.
Decorator wraps a function without modifying the function itself. The result of the wrapping?
- Adds functionality of the function.
- Modifies the behavior of the function.
Let's start with a function in Python. To understand decorators, we need to know the full scope of capabilities of Python functions. Everything in Python is an object. Function is not an exception.
>>> a=10 >>> def f(): ... pass ... >>> class MyClass(): ... pass ... >>> print dir() ['MyClass', '__builtins__', '__doc__', '__name__', '__package__', 'a', 'f']
As we can see, f() is an object, and it's not different from classes (MyClass) or variables (a).
We can assign a function to a variable, so the following lines of code is legally perfect.
def func(): print "func()" funcObj = func funcObj()
Functions can be passed around in the same way other types of object such as strings, integers, lists, etc. Another face of a function in Python is it can accept a function as an argument and return a new function object as shown below.
def myFunction(in_function): def out_function(): pass return out_function
The myFunction is indeed a decorator because by definition a decorator is a function that takes a function object as its argument, and returns a function object.
If we elaborate a little bit more on the function we just defined:
def myFunction(in_function): def out_function(): print "Entry: ", in_function.__name__ in_function() print "Exit: ", in_function.__name__ return out_function
Then, how we invoke our decorator?
Let's look at the example below. We put a simple_function into the decorator (myFunction) as an argument, and get a enhanced_function as a return value from the decorator.
def simple_function(): pass enhanced_function = myFunction(simple_function)
In many cases, we use the same name for the returned function objects as the name of the input function. So, practically, the code should look like this:
def simple_function(): pass simple_function = myFunction(simple_function)
If we apply the decorator syntax to the code above:
@myFunction def simple_function(): pass
Note that the first line @myFunctionas is not a decorator but rather a decorator line or an annotation line, etc. The @ indicates the application of the decorator. A decorator is the function itself which takes a function, and returns a new function. In our case, it is myFunction.
When the compiler passes over this code, simple_function() is compiled and the resulting function object is passed to the myFunction code, which does something to produce a function-like object that is then substituted for the original simple_function().
Also, note that in the line:
simple_function = myFunction(simple_function)
the decorator(myFunction) is rebinding function name to decorator result. So, when the simple_function is later called, it's actually calling the object returned by the decorator.
We've seen the rebinding when we define a static method:
>>> class A: ... def s(x): ... print(x) ... s = staticmethod(s) ... >>> A.s(10) 10
The equivalent code using decorator looks like this:
>>> class A: ... @staticmethod ... def s(x): ... print(x) ... >>> A.s(10) 10
Another example: suppose we have two functions defined this way:
>>> def wrapper(f): ... return f ... >>> def foo(): ... pass ...
Then, the wrapper can be used for rebinding foo() like this:
>>> foo = wrapper(foo)
So, it's a decorator:
>>> @wrapper ... def foo(): ... pass
With a decorator defined as below:
def decorator(f): #process function return f
it automatically maps the following:
@decorator def f(arg): return arg*arg f(123) # output 15129
into the equivalent form as shown below:
def f(arg): print arg*arg f = decorator(f)
The decorator is a callable object that returns a callable object with the same number of argument as
So, decoration maps the following line:
And both of them, produces the same result.
If we want a function that does prefix '$', the decorator can help us:
def dollar(fn): def new(*args): return '$' + str(fn(*args)) return new @dollar def price(amount, tax_rate): return amount + amount*tax_rate print price(100,0.1)
The dollar decorator function takes the price() function, and returns enhanced the output from the original price() after modifying the inner working. Note that the decorator enables us to do it without making any changes on the price() function itself.
So, decorator works as a wrapper, modifying the behavior of the code before and after a target function execution, without the need to modify the function itself, enhancing the original functionality.
We can do with the pound as well:
def pound(fn): def new(*args): return (u"\u00A3").encode('utf-8') + str(fn(*args)) return '$' + str(fn(*args)) return new @pound def price(amount, tax_rate): return amount + amount*tax_rate print price(100,0.1)
def count(f): def inner(*args, **kargs): inner.counter += 1 return f(*args, **kargs) inner.counter = 0 return inner @count def my_fnc(): pass if __name__ == '__main__': my_fnc() my_fnc() my_fnc() print 'my_fnc.counter=',my_fnc.counter
import time def timer(f): def inner(*args, **kargs): t = time.time() ret = f(*args, **kargs) print 'timer = %s' %(time.time()-t) return ret return inner @timer def my_fnc(): pass if __name__ == '__main__': my_fnc()
timer = 5.96046447754e-06
def bold(f): def wrapped(): return '<b>' + f() + '</b>' return wrapped def italic(f): def wrapped(): return '<i>' + f() + '</i>' return wrapped @bold @italic def hello(): return 'hello' print hello()
Running Python Programs (os, sys, import)
Modules and IDLE (Import, Reload, exec)
Object Types - Numbers, Strings, and None
Strings - Escape Sequence, Raw String, and Slicing
Strings - Methods
Formatting Strings - expressions and method calls
Files and os.path
Traversing directories recursively
Regular Expressions with Python
Object Types - Lists
Object Types - Dictionaries and Tuples
Functions def, *args, **kargs
map, filter, and reduce
Sets (union/intersection) and itertools - Jaccard coefficient and shingling to check plagiarism
Hashing (Hash tables and hashlib)
Dictionary Comprehension with zip
The yield keyword
Generator Functions and Expressions
Classes and Instances (__init__, __call__, etc.)
if__name__ == '__main__'
@static method vs class method
Private attributes and private methods
bits, bytes, bitstring, and constBitStream
json.dump(s) and json.load(s)
Python Object Serialization - pickle and json
Python Object Serialization - yaml and json
Priority queue and heap queue data structure
Graph data structure
Dijkstra's shortest path algorithm
Prim's spanning tree algorithm
Functional programming in Python
Remote running a local file using ssh
SQLite 3 - A. Connecting to DB, create/drop table, and insert data into a table
SQLite 3 - B. Selecting, updating and deleting data
MongoDB with PyMongo I - Installing MongoDB ...
Python HTTP Web Services - urllib, httplib2
Web scraping with Selenium for checking domain availability
REST API : Http Requests for Humans with Flask
Blog app with Tornado
Python Network Programming I - Basic Server / Client : A Basics
Python Network Programming I - Basic Server / Client : B File Transfer
Python Network Programming II - Chat Server / Client
Python Network Programming III - Echo Server using socketserver network framework
Python Network Programming IV - Asynchronous Request Handling : ThreadingMixIn and ForkingMixIn
Python Interview Questions I
Python Interview Questions II
Python Interview Questions III
Python Interview Questions IV
Image processing with Python image library Pillow
Python and C++ with SIP
PyDev with Eclipse
Redis with Python
NumPy array basics A
NumPy Matrix and Linear Algebra
Pandas with NumPy and Matplotlib
Batch gradient descent algorithm
Longest Common Substring Algorithm
Python Unit Test - TDD using unittest.TestCase class
Simple tool - Google page ranking by keywords
Google App Hello World
Google App webapp2 and WSGI
Uploading Google App Hello World
Python 2 vs Python 3
virtualenv and virtualenvwrapper
Uploading a big file to AWS S3 using boto module
Scheduled stopping and starting an AWS instance
Cloudera CDH5 - Scheduled stopping and starting services
Removing Cloud Files - Rackspace API with curl and subprocess
Checking if a process is running/hanging and stop/run a scheduled task on Windows
Apache Spark 1.3 with PySpark (Spark Python API) Shell
Apache Spark 1.2 Streaming
bottle 0.12.7 - Fast and simple WSGI-micro framework for small web-applications ...
Flask app with Apache WSGI on Ubuntu14/CentOS7 ...
Fabric - streamlining the use of SSH for application deployment
Ansible Quick Preview - Setting up web servers with Nginx, configure enviroments, and deploy an App
Neural Networks with backpropagation for XOR using one hidden layer
NLP - NLTK (Natural Language Toolkit) ...
RabbitMQ(Message broker server) and Celery(Task queue) ...
OpenCV3 and Matplotlib ...
Simple tool - Concatenating slides using FFmpeg ...
iPython - Signal Processing with NumPy
iPython and Jupyter - Install Jupyter, iPython Notebook, drawing with Matplotlib, and publishing it to Github
iPython and Jupyter Notebook with Embedded D3.js
Downloading YouTube videos using youtube-dl embedded with Python
Machine Learning : scikit-learn ...
Django 1.6/1.8 Web Framework ...
Ph.D. / Golden Gate Ave, San Francisco / Seoul National Univ / Carnegie Mellon / UC Berkeley / DevOps / Deep Learning / Visualization