2013-03-13 1 views
3

Я использую некоторые классы, которые необходимо подключить к базам данных. Соединение действительно необходимо при выполнении реального действия. Я хочу задержать фазу соединения, пока она не понадобится. Для этого я хочу сделать что-то похожее на это:Используйте декоратор класса для реализации поздней инициализации

class MyClass 

    def __init__(self): 
     self.conn = None 

    def connect(self): 
     if self.conn : return 
     self.conn = ConnectToDatabase() 

    @connect 
    def do_something1(self): 
     self.conn.do_something1() 

    @connect 
    def do_something2(self): 
     self.conn.do_something2() 

Но я не знаю, как определить connect декоратора для класса.

Я мог бы, конечно, сделать что-то вроде этого:

def do_something1(self): 
     self.connect() 
     self.conn.do_something1() 

Но использование декораторов кажется более читаемым решение. Является ли это возможным?

ответ

5

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

class MyClass(object): 

    def __init__(self): 
     self._conn = None 

    @property 
    def conn(self): 
     if self._conn is None: 
      self._conn = ConnectToDatabase() 
     return self._conn 

    def do_something1(self): 
     self.conn.do_something1() 

    def do_something2(self): 
     self.conn.do_something2() 

Что касается прямого примера декоратора, играя с ответа FJ в:

def prerequisite(prerequisite_function, *pre_args, **pre_kwargs): 
    def wrapper(func): 
     def wrapped(self, *args, **kwargs): 
      prerequisite_function(self, *pre_args, **pre_kwargs) 
      return func(self, *args, **kwargs) 
     return wrapped 
    return wrapper 

class MyClass(object): 

    def __init__(self): 
     self.conn = None 

    def connect(self): 
     if self.conn is None: 
      self.conn = ConnectToDatabase() 

    @prerequisite(connect) 
    def do_something(self): 
     self.conn.do_something() 

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

+0

Это замечательно, спасибо. Когда я перестану учиться? – dangonfast

+0

Когда ты умрешь. :) –

+0

Если вы перестали учиться, вы устарели и замените более новую модель. – kindall

2

мне нравится подход sr2222 в использовании свойства для получения соединения, однако здесь подход с декораторами, которые могут быть полезными или, по крайней мере, информативными (использование functools.wraps() не является обязательным):

import functools 

def require_connection(f): 
    @functools.wraps(f) 
    def wrapped(self, *args, **kwargs): 
     self.connect() 
     return f(self, *args, **kwargs) 
    return wrapped 

class MyClass(object): 
    def __init__(self): 
     self.conn = None 

    def connect(self): 
     if self.conn : return 
     self.conn = ConnectToDatabase() 

    @require_connection 
    def do_something1(self): 
     self.conn.do_something1() 

    @require_connection 
    def do_something2(self): 
     self.conn.do_something2() 
+0

Я не пробовал, но выглядит интересно. Тем не менее, sr2222 ответ делает проще, что я хотел сделать, и хотя это напрямую отвечает на мой вопрос, я предпочитаю другое решение. – dangonfast

+0

Почему даже сделать этот метод в классе? 'require_connection' будет доступен, но бесполезно бесполезно/сломано в любой момент после создания класса. Либо сделайте его прямой вспомогательной функцией, либо сделайте ее более значимой с метаклассом. –

+0

@ sr2222 Хорошая точка, я переместил 'require_connection' из класса. –

2

Подобно sr2222, но называя это тем, что это такое: a cached_property.

Код более компактный, использует многоразовые строительные блоки и, на мой взгляд, более читаемый.

class MyClass(object): 

    @cached_property 
    def conn(self): 
     return ConnectToDatabase() 

    def do_something1(self): 
     self.conn.do_something1() 

    def do_something2(self): 
     self.conn.do_something2() 

Определение cached_propertyhere найдено.

+0

Декодер 'property' является встроенным, хотя' cached_property' не является. –

+0

правильный. это по-прежнему очень полезный строительный блок. схватите его один раз, используйте его много. – shx2

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

  • Нет связанных вопросов^_^