2013-03-25 3 views
0

Я просто получаю в борьбу с декораторами в Python и использовать их, чтобы добавить обратные вызовы некоторых переменному экземпляра с помощью следующей простой схеме:Могу ли я реорганизовать этот простой обратный шаблон, который использует декоратор свойств?

class A(object): 
    def __init__(self): 
     self._var = 0 
     self.var_callbacks = [] 

    @property 
    def var(self): 
     return self._var 

    @var.setter 
    def var(self, x): 
     self._var = x 
     for f in self.var_callbacks: 
      f(x) 

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

Есть ли способ, чтобы реорганизовать эту картину в чем-то по следующему:

class A(object): 
    def __init__(self): 
     self.var = 0 
     enable_callback(self, 'var', 'var_callbacks') 

ответ

3

Вам нужно установить свойство в классе (так как это дескриптор), поэтому с помощью enable_callback вызова в инициализаторе не будет работать.

Вы можете использовать класс декоратора, чтобы установить свойства из шаблона:

def callback_properties(callbacks_attribute, *names): 
    def create_callback_property(name): 
     def getter(self): 
      return getattr(self, '_' + name) 
     def setter(self, value): 
      setattr(self, '_' + name, value) 
      for f in getattr(self, callbacks_attribute): 
       f(value) 
     return property(getter, setter) 

    def add_callback_properties(cls): 
     for name in names: 
      setattr(cls, name, create_callback_property(name) 

     return cls 

    return add_callback_properties 

Тогда используйте это как:

@add_callback_properties('var_callbacks', 'var1', 'var2') 
class A(object): 
    # everything else 
+0

У вас есть цикл после возвращения заявления – jamylak

+1

Ах, да. Теперь ушла ошибка c & p. –

2

Посмотрите на Python descriptor protocol. В сущности, вы можете определить класс, который обрабатывает получение, настройку и удаление свойства. Таким образом, вы можете определить дескриптор, который запускает ваши обратные вызовы при настройке атрибута.

Дескрипторы являются регулярными классами и могут быть параметризованы. Таким образом, вы можете реализовать дескриптор, который принимает переменную назначения в свой конструктор. Что-то вроде следующего:

class A(object): 
    var = CallbackDescriptor('var') 
    foo = CallbackDescriptor('foo')