使用类装饰器实现延迟初始化
我正在使用一些需要连接数据库的类。其实,只有在执行真正的操作时才需要连接数据库。我想把连接的过程延迟到真正需要的时候。为此,我想做一些类似下面的事情:
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()
不过,使用装饰器似乎是一个更易读的解决方案。这样做可以吗?
3 个回答
2
这段话和sr2222的解决方案类似,但直接称它为一个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
的定义可以在这里找到。
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()
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()
至于一个简单的装饰器示例,可以参考F.J的回答:
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
更强大一点,让它创建描述符,这样它就能正确地处理函数、静态方法、类方法和实例方法了。