Skip to main content

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 function
  • wrapped.args - a tuple of all positional arguments passed to a function
  • wrapped.kwargs - a dict of all keyword arguments passed to a function
  • wrapped.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 arguments
  • simpledeco.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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

SimpleDeco-0.0.3.tar.gz (3.9 kB view details)

Uploaded Source

Built Distribution

SimpleDeco-0.0.3-py3-none-any.whl (4.4 kB view details)

Uploaded Python 3

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

Hashes for SimpleDeco-0.0.3.tar.gz
Algorithm Hash digest
SHA256 502f067fda54a4413101d3658e63157ca8b406dbb455ca143c284cbfeaa3d94b
MD5 f69c3ff272b1b13d89f8fdc031894afb
BLAKE2b-256 79c1b3e3ef3482ed729ab92fd60254741ab26ab505bab252edb117f6e83d2df4

See more details on using hashes here.

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

Hashes for SimpleDeco-0.0.3-py3-none-any.whl
Algorithm Hash digest
SHA256 7bd892f8b2dd1ed3a51f555dbeb04ab5df524b232d79e9b5bd33fbd887db0bee
MD5 d52ffa466143b8c529a3d067e7647464
BLAKE2b-256 9830110aac7a689d0a6dc29de5057d97dd67f6b6be104bf75bb01c0c058bedc3

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page