我的类具有使用@property
装饰器设置的属性。它们使用try和except子句作为getter和setter。如果未设置attribute,它将从数据库获取数据并使用它来从其他类中实例化对象。我试图保持示例简短,但用于实例化属性对象的代码与每个属性略有不同。他们的共同点是尝试 - 开头时除外。
class SubClass(TopClass):
@property
def thing(self):
try:
return self._thing
except AttributeError:
# We don't have any thing yet
pass
thing = get_some_thing_from_db('thing')
if not thing:
raise AttributeError()
self._thing = TheThing(thing)
return self._thing
@property
def another_thing(self):
try:
return self._another_thing
except AttributeError:
# We don't have things like this yet
pass
another_thing = get_some_thing_from_db('another')
if not another_thing:
raise AttributeError()
self._another_thing = AnotherThing(another_thing)
return self._another_thing
...etc...
@property
def one_more_thing(self):
try:
return self._one_more_thing
except AttributeError:
# We don't have this thing yet
pass
one_thing = get_some_thing_from_db('one')
if not one_thing:
raise AttributeError()
self._one_more_thing = OneThing(one_thing)
return self._one_more_thing
我的问题:这是一种正确的(例如pythonic)做事的方式吗?对我来说,在所有内容之上添加try-except-segment似乎有点尴尬。另一方面,它使代码保持简短。或者有更好的方法来定义属性吗?
答案 0 :(得分:6)
只要您至少使用Python 3.2,请使用functools.lru_cache()
装饰器。
import functools
class SubClass(TopClass):
@property
@functools.lru_cache()
def thing(self):
thing = get_some_thing_from_db('thing')
if not thing:
raise AttributeError()
return TheThing(thing)
一个快速可运行的例子:
>>> import functools
>>> class C:
@property
@functools.lru_cache()
def foo(self):
print("Called foo")
return 42
>>> c = C()
>>> c.foo
Called foo
42
>>> c.foo
42
如果您有很多这些,可以组合装饰器:
>>> def lazy_property(f):
return property(functools.lru_cache()(f))
>>> class C:
@lazy_property
def foo(self):
print("Called foo")
return 42
>>> c = C()
>>> c.foo
Called foo
42
>>> c.foo
42
如果你仍然使用旧版本的Python,那么在ActiveState上有一个功能齐全的lru_cache后端,尽管在这种情况下,当你调用它时你没有传递任何参数,你可能会用更多的东西替换它简单。
@YAmikep询问如何访问cache_info()
的{{1}}方法。它有点乱,但您仍然可以通过属性对象访问它:
lru_cache