使用Python延迟加载的模式

时间:2011-04-27 16:55:06

标签: python database

我有dict形式的数据(来自MongoDB数据库,通过PyMongo),如:

car = {_id: "1", "color": "silver", "steering_wheel":"2"}

其中“steering_wheel”的值是我的数据库中另一个文档的id,表示SteeringWheel类的实例。从DB加载到Python将导致:

steering_wheel = {_id: "2", "cover": "plastic"}

要使用数据我使用Python类。现在,我的问题是关于延迟加载。我可以想到两种方式:

1)保留引用的id并创建另一个运行时,仅用于直接访问引用的对象:

class Car(object):
    def __init__(self, _id, color, steering_wheel_ref_id, session):
        self._id = _id
        self.color = color
        self.steering_wheel_ref_id = steering_wheel_ref_id
        self.session = session

    @property
    def steering_wheel(self):
        try:
            return self.steering_wheel
        except AttributeError:
            # Get the referecend object from the session 
            self.steering_wheel = self.session.resolve_item_refs(self.steering_wheel_ref_id)
            return self.steering_wheel

2)另一种选择是进行类型检查:

class Car(object):
    def __init__(self, _id, color, steering_wheel, session):
        self._id = _id
        self.color = color
        self.steering_wheel = steering_wheel
        self.session = session

    @property
    def steering_wheel(self):
        if isinstance(self.steering_wheel, SteeringWheel):
            return self.steering_wheel
        else:
            # Get the referecend object from the session 
            self.steering_wheel = self.session.resolve_item_refs(self.steering_wheel_ref_id)
            return self.steering_wheel

您更喜欢哪种方式?或者是否有更好的方法/最佳实践来解析id?

对引用的访问

4 个答案:

答案 0 :(得分:3)

这个怎么样?

class Car(object):
    def __init__(self, _id, color, steering_wheel_ref_id, session):
        self._id = _id
        self.color = color
        self.steering_wheel_ref_id = steering_wheel_ref_id
        self.session = session
        self._steering_wheel = None

    @property
    def steering_wheel(self):
        if self._steering_wheel is None:
            # Get the referecend object from the session 
            self._steering_wheel = self.session.resolve_item_refs(self.steering_wheel_ref_id)
        return self._steering_wheel

答案 1 :(得分:1)

如果我必须在两种方法中选择一种,我会选择第一种方法。在你使用鸭子打字的意义上它更加pythonic,这是“Python方式”。

第二个更难阅读和理解。

至于其他建议,抱歉,但我一无所获。 : - )

答案 2 :(得分:1)

虽然一般来说它是EAFP,但这并不适用于创建冗余的地方,IMO。

所以:

@property
def steering_wheel(self):
if not hasattr(self, 'steering_wheel'):
    self.steering_wheel = self.session.resolve_item_refs(self.steering_wheel_ref_id)
    # And while we're at it, maybe a bit of housekeeping?
    del self.steering_wheel_ref_id
return self.steering_wheel

说到冗余...如果我们要做很多事情,也许我们应该将这个逻辑封装在自己的Proxy类中:

class DatabaseProxy(object):
    def __init__(self, session, id):
        self.session = session
        self.id = id

    def __getattr__(self, what):
        if what == 'value':
            self.value = self.session.resolve_item_refs(self.id) # cache for next time
            return self.value
        raise AttributeError

class Car(object):
    def __init__(self, _id, color, steering_wheel_ref_id, session):
        self._id = _id
        self.color = color
        self.steering_wheel_proxy = DatabaseProxy(session, steering_wheel_ref_id)
        self.session = session

    @property
    def steering_wheel(self): return self.steering_wheel_proxy.value

类似的东西。

答案 3 :(得分:0)

首选使用duck typing和异常处理的选项。这遵循“更容易请求宽恕而不是许可”(又名EAFP)方法,这在Python中很受欢迎。

这样做的部分原因是,您只需尝试执行操作并处理预期的错误,而不是将类型/类的名称烘焙到代码中。这允许您为IDENTITY上的BEHAVIOR编码。

进一步阅读: