Decorators without nested functions
Project description
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_wrapping
decorates a function that takes wrapped SimpleDeco and wrapper as argumentssimpledeco.before_decorating
decorates 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.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file SimpleDeco-0.0.3.tar.gz
.
File metadata
- Download URL: SimpleDeco-0.0.3.tar.gz
- Upload date:
- Size: 3.9 kB
- Tags: Source
- Uploaded using 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
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 502f067fda54a4413101d3658e63157ca8b406dbb455ca143c284cbfeaa3d94b |
|
MD5 | f69c3ff272b1b13d89f8fdc031894afb |
|
BLAKE2b-256 | 79c1b3e3ef3482ed729ab92fd60254741ab26ab505bab252edb117f6e83d2df4 |
File details
Details for the file SimpleDeco-0.0.3-py3-none-any.whl
.
File metadata
- Download URL: SimpleDeco-0.0.3-py3-none-any.whl
- Upload date:
- Size: 4.4 kB
- Tags: Python 3
- Uploaded using 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
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 7bd892f8b2dd1ed3a51f555dbeb04ab5df524b232d79e9b5bd33fbd887db0bee |
|
MD5 | d52ffa466143b8c529a3d067e7647464 |
|
BLAKE2b-256 | 9830110aac7a689d0a6dc29de5057d97dd67f6b6be104bf75bb01c0c058bedc3 |