Python的延迟加载模式

Python的延迟加载模式,python,database,Python,Database,我有dict形式的数据(通过PyMongo来自MongoDB数据库),如: 其中,“steering_wheel”的值是我的数据库中表示SteeringWheel类实例的另一个文档的id。从DB加载到Python将导致: steering_wheel = {_id: "2", "cover": "plastic"} 为了处理数据,我使用Python类。现在,我的问题是关于延迟加载。我可以想出两种方法: 1) 保留引用的id并创建另一个仅用于运行时的属性,以便直接访问引用的对象: class C

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

其中,“steering_wheel”的值是我的数据库中表示SteeringWheel类实例的另一个文档的id。从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访问引用的问题?

首选使用duck类型和异常处理的第一个选项。这遵循了Python中流行的“请求原谅比允许更容易”(也称为EAFP)方法

部分原因是,您只是试图执行一个操作并处理一个预期的错误,而不是将类型/类的名称烘焙到代码中。这允许您为行为而不是身份编码

进一步阅读:


    • 如果我必须在你的两种方法中选择一种,我会选择第一种。在使用duck类型的意义上,它更像Python,这是“Python方式”

      第二个更难阅读和理解

      至于其他建议,对不起,我什么也没有得到。:-)

      这个怎么样

      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
      

      IMO说,虽然通常是EAFP,但这不适用于创建冗余的地方

      因此:

      说到冗余。。。如果我们要经常这样做,也许我们应该将这个逻辑封装在它自己的代理类中:

      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
      

      类似于此。

      请确保属性和实例属性的名称不要相同,否则会出现一些递归问题。@Daenyth:
      是否在
      =
      之上?为什么?@Rumple高跷:主要是传统。稍微快一点。此外,这是一个好习惯,因为类中重写的
      \uuuuueq\uuuuu
      会导致
      ==None
      的代码执行超出您预期的操作,而
      为None
      不能像那样中断。1。使用
      something is None
      代替
      something==None
      2。使用
      self.\u steering\u wheel
      内部
      def steering\u wheel()
      (注意:前导下划线)否则将导致无限大recursion@Daenyth:谢谢。今天我学到了一些新东西。它实际上是PEP 8的一部分只要
      方向盘
      属性不能有效地设置为
      ,这种方法就可以了。
      @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
      
      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