Python3 decorating conditionally?
Asked Answered
R

4

7

Is it possible to decorate a function based on a condition?

a'la:

if she.weight() == duck.weight(): 
    @burn
def witch():
    pass

I'm just wondering if logic could be used (when witch is called?) to figure out whether or not to decorate witch with @burn?

If not, is it possible to create a condition within the decorator to the same effect? (witch being called undecorated.)

Rabbi answered 22/9, 2010 at 20:55 Comment(0)
S
14

You can create a 'conditionally' decorator:

>>> def conditionally(dec, cond):
    def resdec(f):
        if not cond:
            return f
        return dec(f)
    return resdec

Usage example follows:

>>> def burn(f):
    def blah(*args, **kwargs):
        print 'hah'
        return f(*args, **kwargs)
    return blah

>>> @conditionally(burn, True)
def witch(): pass
>>> witch()
hah

>>> @conditionally(burn, False)
def witch(): pass
>>> witch()
Supernatant answered 5/10, 2010 at 16:6 Comment(2)
+1 I like this more than my solution, as it keeps with the decorator theme, and looks pretty clean, imo.Tetralogy
This is an old answer, but does anyone know how to pass arguments to the conditionally-wrapped decorator using this pattern?Pepi
R
8

It is possible to enable/disable decorators by reassignment.

def unchanged(func):
    "This decorator doesn't add any behavior"
    return func

def disabled(func):
    "This decorator disables the provided function, and does nothing"
    def empty_func(*args,**kargs):
        pass
    return empty_func

# define this as equivalent to unchanged, for nice symmetry with disabled
enabled = unchanged

#
# Sample use
#

GLOBAL_ENABLE_FLAG = True

state = enabled if GLOBAL_ENABLE_FLAG else disabled
@state
def special_function_foo():
    print "function was enabled"
Rabbi answered 30/9, 2010 at 14:1 Comment(0)
T
6

Decorators are just syntactical sugar for re-defining the function, ex:

def wrapper(f):
    def inner(f, *args):
        return f(*args)
    return lambda *args: inner(f, *args)

def foo():
    return 4
foo = wrapper(foo)

Which means that you could do it the old way, before the syntactical sugar existed:

def foo():
    return 4
if [some_condition]:
    foo = wrapper(foo)
Tetralogy answered 5/10, 2010 at 16:17 Comment(0)
S
1

To create a conditional decorator you can create a decorator which accepts arguments as below

from functools import wraps

def burn(condition):
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            if condition:
                ## add witch burning logic here
                result = func(*args, **kwargs)
            else:
                result = func(*args, **kwargs)
            return result
        return wrapper
    return decorator

@burn(condition)
def witch():
    pass
Sporule answered 20/5 at 9:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.