2013-08-05 3 views
4

Надеюсь, что кто-то, кто знаком с процедурами компиляции и выполнения Python, может пролить свет на мой вопрос, связанный с тем, как Python компилирует декоратор.Функция декоратора Python, вызванная во время компиляции

В моем примере кода я включил тестовый отчет печати в декодер «writeit» непосредственно перед закрытием logtofile. Если вы запустили весь код, который я предоставил, для каждого декоратора @writeit, определенного в классе Customer, вызывается запрос печати «test» в printit, прежде чем writeit будет когда-либо использоваться.

Почему во время компиляции вызывается logtofile? Может ли кто-нибудь объяснить это поведение?

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() 
+0

Это не во время компиляции, это во время выполнения. Но для запуска ваших инструкций 'def' в определении класса требуется запуск декораторов, которые их украшают. – geoffspear

ответ

6

Ваш код запускается, когда модуль импортирован. Python выполняет все инструкции верхнего уровня, включая определения классов в то время.

Тело определения класса выполняется как функция, а локальное пространство имен становится атрибутом класса. Это означает, что объекты класса выполняются при импорте, если класс определен на верхнем уровне модуля.

Когда Python встречает украшенную функцию при выполнении, он определит класс, затем выполнит функцию декоратора, передав объект функции и привязывая возвращаемое значение декоратора к имени функции. Поскольку тело класса выполняется во время импорта, это означает, что ваш декоратор выполняется в это время.

+0

Благодарим вас за разъяснение, Martijn. Не могли бы вы рекомендовать какой-либо справочный материал, который я мог бы использовать, чтобы узнать это более подробно? – Dowwie

+0

Вам нужно будет прочитать [ссылку на Python] (http://docs.python.org/2/reference/); что модуль инициализирован при импорте, задокументирован в [модели исполнения] (http://docs.python.org/2/reference/executionmodel.html), и как определяется класс, указан в ['class' compound statement] (http://docs.python.org/2/reference/compound_stmts.html#class-definitions). Применение декораторов является частью описания [определения функций] (http://docs.python.org/2/reference/compound_stmts.html#function-definitions). –

1

Нет времени компиляции. Оператор def и связанные с ним вызовы декоратора являются исполняемыми операциями.

Соответственно, когда Python загружает модуль, он выполняет инструкции в порядке. При выполнении инструкции класса на одном из ранних этапов выполняется выполнение всех операторов в классе. В рамках этого запускаются def s, и эти функциональные объекты будут переданы декораторам для обработки.

Ваш запрос на печать будет выполняться всякий раз, когда вызывается декоратор, а не когда возвращается функция, которую он возвращает. Если вы хотите этого поведения, переместите декоратор во внутреннюю функцию.