2016-05-11 41 views
4

我有一個python類的屬性,在大型數組上執行操作。每次訪問該屬性時,在不重做操作的情況下首次計算該方法後,如何存儲該方法結果的最佳方法是什麼?Pythonic的方法來存儲一個方法的結果作爲一個屬性

例如:

class MyClass: 
    def __init__(self, x, y): 
     """Input variables are two large data arrays""" 
     self.x = x 
     self.y = y 

    @property 
    def calculate(self): 
     """Some computationally expensive operation""" 
     try: 
      # the result has been calculated already 
      return self._result 
     except AttributeError: 
      # if not, calculate it 
      self._result = self.x * self.y 
      return self._result 

用法:

>>> foo = MyClass(2,3) 
>>> a = foo.calculate 
>>> print(a) 
6 

正如你所看到的,我想出了到目前爲止是有一個「隱藏」屬性的結果存儲在哪裏。有一個更好的方法嗎?這裏使用的是@property嗎?

謝謝。

+3

退房https://github.com/pydanny/cached-property –

+2

如何初始化的對象與'self._result = None',然後在'calculate'您先檢查是否'self._result '在計算新產品之前已經有了價值? – TigerhawkT3

+1

我個人不會在這裏使用'@ property',因爲從邏輯上講,你期望稱爲「calculate」的東西是一個可以工作的函數。 – Paul

回答

1

基本上看起來不錯。但由於xy是可變的,所以在xy將被修改的情況下,您將需要使_result無效。

我會使xy屬性,以及一旦他們將被設置無效_result

的一件事,因爲xylists引用(我猜你意思是說arrays時),這些列表可能會從MyClass範圍之外的修改。如果發生這種情況,按照我的建議使用屬性,MyClass將無法​​檢測到更改,即使xy是屬性。我會忍受這種限制,但要記錄下來。

+0

儘管如此,您無法真正檢測到這種修改。 – user2357112

+0

我會用'x'和'y'來做一個屬性。檢查我的更新。 – hek2mgl

+0

當然,你可以很容易地檢測到設置屬性(只要用戶不繞過屬性),但是我正在考慮更多的沿着用戶的行,只是突變他們通過的數組。 – user2357112

0

您可以將對象初始化爲None,然後檢查是否仍然None

class MyClass: 
    def __init__(self, x, y): 
     """Input variables are two large data arrays""" 
     self.x = x 
     self.y = y 
     self._result = None 

    @property 
    def calculate(self): 
     """Some computationally expensive operation""" 
     if self._result is not None: 
      return self._result 
     # if not, calculate it 
     self._result = self.x * self.y 
     return self._result 
3

你要記住,用於計算高速緩存的結果爲x和y的值。如果它們發生變化,則需要重新計算並刷新緩存。

class MyClass: 
    def __init__(self, x, y): 
     """Input variables are two large data arrays""" 
     self.x = x 
     self.y = y 
     self._calculate = None 
     self._x = None 
     self._y = None 

    @property 
    def calculate(self): 
     if not self._calculate or self._x != self.x or self._y != self.y: 
      self._calculate = self.x * self.y 
      self._x = self.x 
      self._y = self.x 

     return self._calculate 


>>> a = MyClass(2,3) 
>>> print(a.calculate) 
6 
>>> a.x = 553 
>>> print(a.calculate) 
1659 
+0

這是可靠的檢測結果需要重新計算,是的。但是,當x和y是大數組時,副本的額外內存消耗和比較工作量不應低估。 – hek2mgl

+0

當然,全部取決於數據大小和使用情況。記住多個過去的結果並建立過去的「x,y,結果」字典的存儲列表也是一個好主意。 – C14L

+0

我沒有看到回憶x和y的任何方法。如何在不知道查找的情況下緩存某些內容?如果x和y是小於100K的內存大小爲1MB的浮動列表。如果它們比使用Python之外的東西實現高速緩存更大,即沒有簡單的方法來緩存1M +記錄。 – Charlie

2

你實現你的財產的方式就好了。它的工作原理,幾乎沒有開銷。

作爲一個思想實驗,您可以利用非數據描述符的特定屬性。非數據描述符類似於property(這是一個數據描述符)。非數據描述符是僅定義__get__方法的對象。當實例具有與非數據描述符同名的屬性時,將覆蓋非數據描述符(請考慮猴子修補函數)。例如。

class cache: 
    def __init__(self, func): 
     self.func = func 

    def __get__(self, obj, type_): 
     if obj is None: 
      return self.func 
     value = self.func(obj) 
     setattr(obj, self.func.__name__, value) 
     return value 

class MyClass: 
    def __init__(self, x, y): 
     self.x = x 
     self.y = y 

    @cache 
    def calculate(self): 
     print("calculating") 
     return self.x + self.y 

o = MyClass(1, 2) 
print("first", o.calculate) # prints "calcutating" then "first 3" 
print("second", o.calculate) # just prints "second 3" 
del o.calculate 
print("third", o.calculate) # prints "calcutating" then "third 3" 
相關問題