16

I think the answer is no, but I can't seem to find a definitive claim. I have the following situation;

def decorated_function(function):
    @functools.wraps(function)
    def my_function():
        print "Hello %s" % function.__name__
    return my_function

for attr, value in dct.iteritems():
    dct[attr] = decorated_function(value)

And what I really want is something like;

def my_function(function):
    print "Hello %s" % function.__name__

for attr, value in dct.iteritems():
    dct[attr] = functools.wraps(my_function, value)

to remove the confusing shell of decorated_function. Are decorators only possible to apply when the function is defined?

Alex Altair
  • 3,246
  • 3
  • 21
  • 37
  • 2
    I'm not sure what you are doing here. functools.wraps is just a small utility to copy the name and doc attributes to the decorated function, it doesn't do anything to change the functionality. What are you trying to achieve? – Daniel Roseman Feb 26 '15 at 12:05
  • 1
    Decorators are just regular functions + syntactic sugar that allows applying them conveniently, but the latter is optional. So, the answer is yes. – bereal Feb 26 '15 at 12:09
  • Possible duplicate of [How can one attach a decorator to a function "after the fact" in python?](https://stackoverflow.com/questions/33868886/how-can-one-attach-a-decorator-to-a-function-after-the-fact-in-python) – darthbith Jun 30 '18 at 19:06

1 Answers1

27

You can decorate functions after they have been defined. In fact, function decorators are only syntactic sugar. For example, you can replace

@classmethod
@synchronized(lock)
def foo(cls):
    pass

with

def foo(cls):
    pass
foo = synchronized(lock)(foo)
foo = classmethod(foo)

See https://www.python.org/dev/peps/pep-0318/ for details.

Till Hoffmann
  • 9,479
  • 6
  • 46
  • 64
  • 1
    Any tips on how to deal with `UnboundLocalError: local variable 'foo' referenced before assignment`? Eg, function defined at the top level and decorated version being declared in main?. - Edit, seems you have to `global foo` the line before; does that make the assignment overload foo for this whole namespace? - Edit You can also name the local version soemthing else `sync_foo = synchronized(foo)` – ThorSummoner Jan 06 '17 at 22:47
  • 2
    Yes, if you declare `foo` global, it will also modify `foo` in all other name scopes. However, your last suggestion of `sync_foo` is probably the best idea: it leaves the global `foo` unchanged and your local, modified version is clearly distinguished to avoid confusion. – Till Hoffmann Jan 09 '17 at 09:57