2013-07-23 2 views
1

У меня есть следующий код:Как Python имен декоратор разрешать

import threading 
from functools import wraps 
class Synchronized(object): 
    def __init__(self): 
     self.lock = threading.Lock() 

    def synchronized(f): 
     @wraps(f) 
     def wrapper(self, *args, **kwargs): 
      with self.lock: 
       print "here" 
       return f(self, *args, **kwargs) 
     return wrapper 

    @synchronized 
    def go(self): 
     print 1 

class B(Synchronized): 
    @synchronized 
    def foo(self): 
     return 1 

Этот код терпит неудачу на импорт жалуясь:

File "a.py", line XXX, in B 
    @synchronized 
NameError: name 'synchronized' is not defined 

Однако, если я закомментировать B и просто использовать Syncrhonized().go() он прекрасно работает.

Вопрос: Как питон знать, что в базовом классе @synchronized, но не решить ее в его производных?

+3

Почему вы хотите, чтобы синхронизировался как метод, а не как функция? – bereal

+0

Потому что я хочу сохранить его внутри класса для лучшей организации кода. –

ответ

4

synchronized определяется как функция в корпусе класса Synchronizedтолько.

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

Вы можете использовать @Syncronized.synchronized.im_func в классе B (.im_func разворачивать функцию от метода обертки):

class B(Synchronized): 
    @Synchronized.synchronized.im_func 
    def foo(self): 
     return 1 

еще лучше, не определен декоратора внутри класса на всех, но вместо того, чтобы определить его снаружи от Synchronized. В конце концов, это не метод:

def synchronized(f): 
    @wraps(f) 
    def wrapper(self, *args, **kwargs): 
     with self.lock: 
      print "here" 
      return f(self, *args, **kwargs) 
    return wrapper 

class Synchronized(object): 
    def __init__(self): 
     self.lock = threading.Lock() 

    @synchronized 
    def go(self): 
     print 1 

class B(Synchronized): 
    @synchronized 
    def foo(self): 
     return 1 
+0

Спасибо за объяснение. Да, я знаю, что могу определить декоратор вне класса, но тогда вам нужно импортировать две вещи, если вы используете его как вспомогательный режим. В качестве альтернативы я могу украсить synchronized с помощью @staticmethod и использовать его только в производных классах. –

+1

Вы также можете использовать его в базе: '@synchronize .__ func__'. –

Смежные вопросы