SimpleDeco
Decorators without nested functions
SimpleDeco is a way to create decorators with arguments and not to think about higher-order functions.
Instead, of nested functions, with SimpleDeco you split the decorator definitions into one or more plain functions.
Basic example
Let's create a count_time(iterations) decorator, which runs the given function the given number of iterations and counts the average time.
from time import time
from src.simpledeco import SimpleDeco, Wrapped
@SimpleDeco
def count_time(wrapped: Wrapped, iterations: int):
t1 = time()
for _ in range(iterations):
# run the wrapped func with given arguments
wrapped.func(*wrapped.args, **wrapped.kwargs)
t2 = time()
print('time:', (t2 - t1) / iterations)
@count_time(1000)
def f(x, y):
return sum(range(x, y))
# Counts the sum of numbers from 1 to 50000 for 1000 times
# and prints the average time
f(1, 50000)
The similar code without SimpleDeco:
from time import time
def count_time(iterations: int):
def decorator(func):
def wrapper(*args, **kwargs):
t1 = time()
for _ in range(iterations):
func(*args, **kwargs)
t2 = time()
print('time:', (t2 - t1) / iterations)
return wrapper
return decorator
@count_time(1000)
def f(x, y):
return sum(range(x, y))
f(1, 50000)
Pretty more complex.
Wrapped object
SimpleDeco objects (like count_time above) are callable objects, which return decorators.
When using a SimpleDeco object with arguments as a decorator, the Wrapped instance and given arguments
are passed.
Wrapped object has simple attributes:
wrapped.func- the given functionwrapped.args- a tuple of all positional arguments passed to a functionwrapped.kwargs- a dict of all keyword arguments passed to a functionwrapped.arguments- an object with all passed arguments
Thus, you can use wrapped.func(*wrapped.args, **wrapped.kwargs) to call the original function with original arguments.
If you need to use specific arguments, use wrapped.arguments attributes. For example, if you need to decorate only functions with x and y arguments:
@SimpleDeco
def count_time(wrapped: Wrapped, iterations: int):
t1 = time()
for _ in range(iterations):
wrapped.func(wrapped.arguments.x, wrapped.arguments.y)
t2 = time()
print('x:', wrapped.arguments.x, 'y:', wrapped.arguments.y)
print('time:', (t2 - t1) / iterations)
Hooks
Sometimes you need to do something after wrapping a function or before decorating it. There are special SimpleDeco methods for that.
simpledeco.after_wrappingdecorates a function that takes wrapped SimpleDeco and wrapper as argumentssimpledeco.before_decoratingdecorates a function that takes wrapped SimpleDeco and decorator as arguments
For example:
from time import time
from src.simpledeco import SimpleDeco
@SimpleDeco
def count_time(wrapped, iterations):
t1 = time()
for _ in range(iterations):
# run the wrapped func with given arguments
wrapped.func(*wrapped.args, **wrapped.kwargs)
t2 = time()
print('time:', (t2 - t1) / iterations)
@count_time.after_wrapping
def after_wrapping(count_time_wrapped, wrapper):
print('Running function for', count_time_wrapped.arguments.iterations, 'times')
print('With arguments (1, 50000)')
wrapper(1, 50000)
@count_time.before_decorating
def before_decorating(count_time_wrapped, decorator):
print('Generated decorator with argument:', count_time_wrapped.arguments.iterations)
# 'decorator' is the generated decorator
@count_time(1000)
def f(x, y):
return sum(range(x, y))
The output:
Generated decorator with argument: 1000
Running function for 1000 times
With arguments (1, 50000)
time: 0.0022199389934539795
Compare with similar code without SimpleDeco:
from time import time
def count_time(iterations: int):
def decorator(func):
def wrapper(*args, **kwargs):
t1 = time()
for _ in range(iterations):
func(*args, **kwargs)
t2 = time()
print('time:', (t2 - t1) / iterations)
print('Running function for', iterations, 'times')
print('With arguments (1, 50000)')
wrapper(1, 50000)
return wrapper
print('Generated decorator with argument:', iterations)
return decorator
@count_time(1000)
def f(x, y):
return sum(range(x, y))
License
This project is licensed under the terms of the MIT license.
Metadata
Release files for SimpleDeco 0.0.3
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| SimpleDeco-0.0.3.tar.gz | 3.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| SimpleDeco-0.0.3-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 8.3 kB
Release files / SimpleDeco-0.0.3.tar.gz
| Download URL | SimpleDeco-0.0.3.tar.gz |
|---|---|
| Size | 3.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
502f067fda54a4413101d3658e63157ca8b406dbb455ca143c284cbfeaa3d94b
|
|
BLAKE2b-256 checksum How to use checksums |
79c1b3e3ef3482ed729ab92fd60254741ab26ab505bab252edb117f6e83d2df4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/3.4.2 importlib_metadata/4.8.1 pkginfo/1.7.1 requests/2.26.0 requests-toolbelt/0.9.1 tqdm/4.62.3 CPython/3.10.0
|
Release files / SimpleDeco-0.0.3-py3-none-any.whl
| Download URL | SimpleDeco-0.0.3-py3-none-any.whl |
|---|---|
| Size | 4.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
7bd892f8b2dd1ed3a51f555dbeb04ab5df524b232d79e9b5bd33fbd887db0bee
|
|
BLAKE2b-256 checksum How to use checksums |
9830110aac7a689d0a6dc29de5057d97dd67f6b6be104bf75bb01c0c058bedc3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/3.4.2 importlib_metadata/4.8.1 pkginfo/1.7.1 requests/2.26.0 requests-toolbelt/0.9.1 tqdm/4.62.3 CPython/3.10.0
|