我正在一個項目中,我有一些自定義類來與用戶系統上的各種數據集合接口。這些類只有properties
作爲面向用戶的屬性。其中一些屬性的資源密集程度相當高,所以我只想運行一次代碼,並將返回的值存儲在磁盤上(緩存即可),以便在後續運行中更快地檢索。既然這樣,這是怎麼了實現這一點:類裝飾器自動更新磁盤上的屬性字典?
def stored_property(func):
"""This ``decorator`` adds on-disk functionality to the `property`
decorator. This decorator is also a Method Decorator.
Each key property of a class is stored in a settings JSON file with
a dictionary of property names and values (e.g. :class:`MyClass`
stores its properties in `my_class.json`).
"""
@property
@functools.wraps(func)
def func_wrapper(self):
print('running decorator...')
try:
var = self.properties[func.__name__]
if var:
# property already written to disk
return var
else:
# property written to disk as `null`
return func(self)
except AttributeError:
# `self.properties` does not yet exist
return func(self)
except KeyError:
# `self.properties` exists, but property is not a key
return func(self)
return func_wrapper
class MyClass(object):
def __init__(self, wf):
self.wf = wf
self.properties = self._properties()
def _properties(self):
# get name of class in underscore format
class_name = convert(self.__class__.__name__)
# this is a library used (in Alfred workflows) for interacted with data stored on disk
properties = self.wf.stored_data(class_name)
# if no file on disk, or one of the properties has a null value
if properties is None or None in properties.values():
# get names of all properties of this class
propnames = [k for (k, v) in self.__class__.__dict__.items()
if isinstance(v, property)]
properties = dict()
for prop in propnames:
# generate dictionary of property names and values
properties[prop] = getattr(self, prop)
# use the external library to save that dictionary to disk in JSON format
self.wf.store_data(class_name, properties,
serializer='json')
# return either the data read from file, or data generated in situ
return properties
#this decorator ensures that this generating code is only run if necessary
@stored_property
def only_property(self):
# some code to get data
return 'this is my property'
此代碼的工作正是因爲我需要它,但它仍然迫使我到_properties(self)
方法手動添加到每個班級,其中我需要這個功能(目前,我有3)。我想要的是將這個功能「插入」任何我喜歡的課程的方法。我認爲一個類裝飾器可以完成這項工作,但儘可能地嘗試,我不能完全弄清楚如何解決它。
爲了清楚起見(如果裝飾者不是獲得我想要的最佳方式),我將嘗試解釋我所追求的整體功能。我想寫一個包含一些屬性的類。這些屬性的值是通過不同程度的複雜代碼生成的(在一個實例中,我正在搜索某個應用程序的pref文件,然後搜索3個不同的首選項(其中任何可能存在或不存在),並確定最佳單個來自這些偏好)。我希望屬性代碼的主體只包含查找數據的算法。但是,我不想每次訪問該屬性時都運行該算法代碼。一旦我產生了一次這個值,我想把它寫到磁盤上,然後在隨後的所有調用中讀取它。但是,我不希望每個值寫入它自己的文件;我想要一個單個類的所有屬性值的字典都寫入一個文件(因此,在上例中,my_class.json
將包含帶有一個鍵值對的JSON字典)。直接訪問屬性時,應首先檢查它是否已存在於磁盤字典中。如果是這樣,只需閱讀並返回該值。如果它存在但是有一個空值,那麼嘗試運行代碼(即實際寫在屬性方法中的代碼)並查看是否可以現在找到它(如果不存在,該方法將返回None
,並且將再次寫入文件)。如果字典存在,並且該屬性不是關鍵字(我當前的代碼並不能真正實現這一點,但比對不起更安全),請運行代碼並添加鍵值對。如果字典不存在(即該類的第一個實例化),請運行所有屬性的所有生成代碼並創建JSON文件。理想情況下,代碼將能夠更新JSON文件中的一個屬性,而無需重新運行所有的代碼(即再次運行_properties()
)。
我知道這有點奇怪,但我需要速度,人類可讀的內容和優雅的代碼。我真的不必在我的目標上妥協。希望我的描述足夠清楚。如果沒有,請在評論中告訴我什麼是沒有道理的,我會盡力澄清。但我認爲一個類裝飾器可能會讓我在那裏(主要是通過將_properties()
方法插入到任何類中,在實例化中運行它,並將其值映射到該類的properties
屬性)。
偉大的一點。我只是現在完全抽象了_properties()方法,並沒有意識到,一旦我抽象出來,我可以使用基類。這似乎比使用類裝飾器更清潔,更具溝通性。 – smargh 2014-11-05 20:40:47