2011-04-27 81 views
2

我有一個字典(從經由PyMongo MongoDB數據庫推出)的形式的數據,如:模式的延遲加載與Python

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

其中「steering_wheel」的值是另一個文檔的ID在我的數據庫代表了SteeringWheel類的一個實例。從數據庫加載到Python將導致:

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

要處理數據,我使用Python類。現在,我的問題是關於延遲加載。我能想到的方法有兩種:

1)保持引用的ID,並創建另一個運行時只attribut直接訪問引用的對象:

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訪問引用?

+0

只要確保不要爲屬性和實例屬性使用相同的名稱,否則會出現一些遞歸問題。 – 2011-04-27 17:10:44

回答

0

首選使用鴨子打字和異常處理的選項。這遵循Python更受青睞的「容易請求原諒而非許可」(又名EAFP)方法。

這樣做的部分原因是,代替在代碼中烘焙類型/類的名稱,您只是試圖執行操作並處理預期的錯誤。這使您可以爲IDENTITY上的行爲編碼。

延伸閱讀:

1

如果我有你的兩個方法之一之間選擇,我會與第一去。在你使用duck-typing這個意義上說,它更像pythonic,這就是「Python方式」。

第二個難以閱讀和理解。

至於其他建議,抱歉,但我什麼也沒得到。 :-)

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 
+0

@Daenyth:'is' over'=='?爲什麼? – 2011-04-27 17:40:11

+0

@Rumple Stiltskin:大多數會議。它稍微快一點。此外,這是一種好習慣,因爲在類中被重載的'__eq__'可以使用'== None'來執行代碼而不是您期望的操作,而'None'不能像那樣打破。 – Daenyth 2011-04-27 17:44:17

+1

1.使用'something是None'而不是'something == None' 2.在'def steering_wheel()'(注意:引導下劃線)內使用'self._steering_wheel',否則會導致無限遞歸 – jfs 2011-04-27 17:48:00

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 

類似的東西。