Sorry for long question, but I don’t know how to make it shorter.
1. Decorators without args
Implementation 1.1 (through function)
import time
import functools
def pause(f):
@functools.wraps(f)
def wrapper(*args, **kwargs):
time.sleep(1)
return f(*args, **kwargs)
return wrapper
@pause
def func(x, y):
"""desc"""
return x + y
print func(1, 2)
help(func)
Output:
3
Help on function func in module __main__:
func(*args, **kwargs)
desc
It’s "classical" implementation – a lot of articles contain it.
-breaks function signature (can be solved by nonstandard module decorator)
-you must use functools for saving name and doc string of function (not very big problem, but slightly more code and magic)
+you can modify function args (not always necessary)
+-? Anything else?
Implementation 1.2 (through function)
import time
def pause(f):
time.sleep(1)
return f
@pause
def func(x, y):
return x + y
print func(1, 2)
help(func)
Output:
3
Help on function func in module __main__:
func(x, y)
desc
? Why it implementation rarely used in articles and examples? What have I missed?
-you can’t modify function args
+not breaks function signature
+less code
+-? Anything else?
Implementation 1.3 (through classes)
import time
class pause(object):
def __init__(self, f):
self.f = f
def __call__(self, *args, **kwargs):
time.sleep(1)
return self.f(*args, **kwargs)
@pause
def func(x, y):
"""desc"""
return x + y
print func(1, 2)
help(func)
Output:
3
Help on pause in module __main__ object:
class pause(__builtin__.object)
| Methods defined here:
|
| __call__(self, *args, **kwargs)
|
| __init__(self, f)
|
| ----------------------------------------------------------------------
| Data descriptors defined here:
|
| __dict__
| dictionary for instance variables (if defined)
|
| __weakref__
| list of weak references to the object (if defined)
IMHO, ugly.
Implementation 1.4 (through classes)
import time
class pause(object):
def __call__(self, f):
time.sleep(1)
return f
@pause()
def func(x, y):
"""desc"""
return x + y
print func(1, 2)
help(func)
Output:
3
Help on function func in module __main__:
func(x, y)
desc
-you can’t modify function args
-nonstandard syntax for decorator use
+not breaks function signature
+-less code (but more than implementation 2 🙂 )
+-? Anything else?
2. Decorators with args
Implementation 2.1 (through function)
import time
import functools
def pause(t):
def wrapper(f):
@functools.wraps(f)
def tmp(*args, **kwargs):
time.sleep(t)
return f(*args, **kwargs)
return tmp
return wrapper
@pause(1)
def func(x, y):
"""desc"""
return x + y
print func(1, 2)
help(func)
Output:
3
Help on function func in module __main__:
func(*args, **kwargs)
desc
It’s "classical" implementation – a lot of articles contain it.
-breaks function signature
-nested is worse than flat
-you must use functools for saving name and doc string of function
+you can modify function args
+-? Anything else?
Implementation 2.2 (through function)
import time
def pause(t):
def wrapper(f):
time.sleep(t)
return f
return wrapper
@pause(1)
def func(x, y):
"""desc"""
return x + y
print func(1, 2)
help(func)
Output:
3
Help on function func in module __main__:
func(x, y)
desc
? Why it implementation rarely used in articles and examples? What have I missed?
-you can’t modify function args
+not breaks function signature
+less code
+-? Anything else?
Implementation 2.3 (through classes)
import time
class pause(object):
def __init__(self, darg):
self.darg = darg
def __call__(self, f):
time.sleep(self.darg)
return f
@pause(1)
def func(x, y):
"""desc"""
return x + y
print func(1, 2)
help(func)
Output:
3
Help on function func in module __main__:
func(x, y)
desc
-you can’t modify function args
+not breaks function signature
+-less code (but more than implementation 2 🙂 )
IMHO+ little clearer than nested functions
+-? Anything else?
Questions in one place
- Why implementations 1.1/2.1 are more common in articles and examples as compared with implementations 1.2/2.2?
- What are the pros and cons I missed?
- Did I missed something else?
It sure is good that the implementations 1.2 & 2.2 are “less common than” 1.1 and 2.1, because they do different things. In fact, I wouldn’t call them “decorators”, because they don’t really wrap (“decorate”) the function. Instead, they only perform their action once, at the moment the decorated function is parsed. That is, their action (sleep in your case) is performed at function definition time, not at function invocation time.
Try invoking your decorated functions several times and you will see the difference.