0

Background

I was reading Python decorators (where I'm a bit of rookie to the concept) and came across a part that emphasises the difference between 'import time' and 'runtime'.

So let's say I have a decorator function in one module called decorator_functions.py and I have another module that houses bunch of decorated functions which is called decorated_objects.py. When I import decorated_objects.py somewhere else, Python creates bindings behind the scenes between the decorated objects and the relevant decorator before even the execution flow run them somewhere. My questions above arise at this point.

I have two questions:

  1. Do the bindings of a decorator stay with the decorated object for as long as the process is in use? That is, what is the lifetime of a decorator in Python after it is bound to an object?
  2. When a decorator is bound to multiple classes or modules which can be executed in multiple threads, are the decorated objects thread-safe? Or do I need to take care of synchronisation (or is there a built-in auto-sync method for decorators?

PS: I've seen this thread but it doesn't address my questions totally.

Scott Skiles
  • 3,647
  • 6
  • 40
  • 64
stdout
  • 2,471
  • 2
  • 31
  • 40

1 Answers1

1

Regarding your first question, function objects are first class objects in python (there is great info here What are "first class" objects?), and the objects created are kept in the workspace of the module as long as it is used. They are not destroyed; unless they are instance methods which gets 'killed' when the object has no more references to it.

The import statement combines two operations; it searches for the named module, then it binds the results of that search to a name in the local scope.

Regarding the second question, each binding returns a new function object. So if you use the same decorator for multiple functions, there is no problem with it as they are different bounded objects.


def decorator(f):
    def decorated_f(*args, **kwargs):
        print 'decorated func'
        f(*args, **kwargs)
    return decorated_f


@decorator
def func1(arg):
    print 'this is func1: ' + arg

@decorator
def func2(arg):
    print 'this is func2: ' + arg


func1('hey there')
func2('hey there')
print func1
print func2

This prints the following output. Notice how the decorated_f are two different objects:

decorated func
this is func1: hey there
decorated func
this is func2: hey there
<function decorated_f at 0x0000000004109588>
<function decorated_f at 0x0000000004109668>
Chen A.
  • 10,140
  • 3
  • 42
  • 61
  • 1
    First answer is clear. For the second answer, I was thinking the same about 'the' inner function itself but was not so sure about free variables that might potentially be used inside the inner function. I think they are also in the local scope of each binding which means they're thread-safe. – stdout Sep 10 '17 at 20:08