9

I hope that someone familiar with Python's compilation / run-time procedures could shed some light on my question relating to how Python compiles decorator functions.

Within my sample code, I've included a testing print statement in the "writeit" decorator just before the logtofile closure is defined. If you run the entire code that I've provided, the "testing" print statement in writeit is called for each @writeit decorator defined in the Customer class-- before writeit is ever used.

Why is logtofile being called at compile time? Could someone please explain this behavior?

def writeit(func): 
    print('testing')

    def logtofile(customer, *arg, **kwargs):
        print('logtofile')
        result = func(customer, *arg, **kwargs)        
        with open('dictlog.txt','w') as myfile:
            myfile.write(func.__name__)
        return result

    return logtofile

class Customer(object):
    def __init__(self,firstname,lastname,address,city,state,zipcode):        
        self._custinfo = dict(firstname=firstname,lastname=lastname,address=address,city=city,state=state,zipcode=zipcode)        

    @writeit
    def setFirstName(self,firstname):
        print('setFirstName')
        self._custinfo['firstname']=firstname

    @writeit
    def setLastName(self,lastname):
        print('setLastName')
        self._custinfo['lastname']=lastname

    @writeit
    def setAddress(self,address):
        print('setAddress')
        self._custinfo['address']=address

def main():
    cust1 = Customer('Joe','Shmoe','123 Washington','Washington DC','DC','12345')
    cust1.setFirstName('Joseph')
    cust1.setLastName('Shmoestein')

if(__name__ == '__main__'): main()
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
Dowwie
  • 1,893
  • 3
  • 18
  • 23
  • It's not at compile time, it's at run time. But running your `def` statements in the class definition requires running the decorators that decorate them. – Wooble Aug 05 '13 at 15:57

2 Answers2

9

Your code runs when the module is imported. Python executes all top-level statements, including class definitions at that time.

A class definition body is executed as a function, with the local namespace becoming the class attributes. This means that class bodies are executed on import, provided the class is defined at the top-level of the module.

When Python encounters a decorated function when executing, it'll define the class, then execute the decorator function, passing in the function object and binding the return value of the decorator to the name of the function. Since the class body is executed during import, this means your decorator is executed at that time.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • Thank you for clarifying, Martijn. Could you recommend any reference material that I could use to learn this in greater detail? – Dowwie Aug 05 '13 at 16:06
  • 1
    You'd have to read through the [Python reference](http://docs.python.org/2/reference/); that a module is initialized on import is documented in the [execution model](http://docs.python.org/2/reference/executionmodel.html), and how a class is defined is specified in the [`class` compound statement](http://docs.python.org/2/reference/compound_stmts.html#class-definitions) reference. How decorators are applied is part of the [function definitions](http://docs.python.org/2/reference/compound_stmts.html#function-definitions) reference. – Martijn Pieters Aug 05 '13 at 16:09
2

There is no compile time. A def statement, and the associated decorator calls are executable statements.

Accordingly, when Python loads a module, it executes the statements in order. When executing a class statement, one of the early stages is executing all of the statements in the class body. As part of that defs are run to create functions, and those function objects will be passed to decorators for processing.

Your "testing" print statement will run whenever the decorator is called, not when the function it returns is called. If you want that behaviour, move the decorator into the inner function.

Marcin
  • 48,559
  • 18
  • 128
  • 201