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.2.tar.gz (4.0 kB view details)

Uploaded Source

Built Distribution

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

Uploaded Python 3

File details

Details for the file SimpleDeco-0.0.2.tar.gz.

File metadata

  • Download URL: SimpleDeco-0.0.2.tar.gz
  • Upload date:
  • Size: 4.0 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.2.tar.gz
Algorithm Hash digest
SHA256 7695f89b001b65a1267cba56577cb1d86021092dce47f8cf9bc84f069f28310d
MD5 766ec7994763f217ac7088c91ee6e54d
BLAKE2b-256 2c7ca065d19798b2e1b852c583773b7ec7e92a9f61dd278c63e12a63acb4f269

See more details on using hashes here.

File details

Details for the file SimpleDeco-0.0.2-py3-none-any.whl.

File metadata

  • Download URL: SimpleDeco-0.0.2-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.2-py3-none-any.whl
Algorithm Hash digest
SHA256 2159373f0a3c89e45a892af05ee9932194dfece0d3e30b2c6dd2112da2e09d7a
MD5 84e46edadf9d725c1b493d3a74abad72
BLAKE2b-256 ea9a29b319a8c7dc954a98eb204b1370e0bcf35bb5e72e53f7c20782ad57adc1

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