4

我正在使用一些需要连接到数据库的类。只有在执行实际操作时才真正需要连接。我想延迟连接阶段,直到真正需要它。为此,我想做类似的事情:

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

但是使用装饰器似乎是一种更具可读性的解决方案。是否可以?

4

3 回答 3

6

与其尝试装饰需要连接的函数,不如使用属性来获取连接本身。

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通过使其创建描述符来使其更加健壮,以便它可以正确地处理函数和静态方法以及类和实例方法。

于 2013-03-13T17:24:21.607 回答
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()
于 2013-03-13T17:35:52.443 回答
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_property可在此处找到。

于 2013-03-13T18:01:04.393 回答