2013-04-16 86 views
4

在蟒蛇,它是壞的形式寫一個__init__定義,如:在初始化的變量是對函數的調用返回一個字符串Python類__init__佈局?

class someFileType(object): 
    def __init__(self, path): 
     self.path = path 
     self.filename = self.getFilename() 
     self.client = self.getClient() 
     self.date = self.getDate() 
     self.title = self.getTitle() 
     self.filetype = self.getFiletype() 
    def getFilename(self): 
     '''Returns entire file name without extension''' 
     filename = os.path.basename(self.path) 
     filename = os.path.splitext(filename) 
     filename = filename[0] 
     return filename 
    def getClient(self): 
     '''Returns client name associated with file''' 
     client = self.filename.split() 
     client = client[1] # Assuming filename is formatted "date client - docTitle" 
     return client 

?或者它被認爲是懶惰的編碼?無論何時我想引用文件的某些方面,主要是爲了將something.filetype當作something.getFiletype()來救我。

此代碼是按客戶端將文件分類到文件夾中,然後通過文檔類型和基於文件名中數據的其他操作。

+0

完全沒問題。即使更容易閱讀。 –

+0

對我來說看起來很好,除非你的一個getFoo()函數碰巧需要很長時間,在這種情況下,你可能需要推遲它,直到它實際需要。 – Aya

+1

我寧願緩存@property。 – kay

回答

11

不,我不明白爲什麼這將是不好的形式。事實上,創建實例時只計算一次這些值可能是一個好主意。

你也可以直到需要通過使用緩存property小號推遲算了一筆賬:

class SomeFileType(object): 
    _filename = None 
    _client = None 

    def __init__(self, path): 
     self.path = path 

    @property 
    def filename(self): 
     if self._filename is None: 
      filename = os.path.basename(self.path) 
      self._filename = os.path.splitext(filename)[0] 
     return self._filename 

    @property 
    def client(self): 
     '''Returns client name associated with file''' 
     if self._client is None: 
      client = self.filename.split() 
      self._client = client[1] # Assuming filename is formatted "date client - docTitle" 
     return self._client 

現在,訪問somefiletypeinstance.client將引發self.filename按需計算,以及高速緩存它自己的計算結果。

在這種特定情況下,您可能還想要.path屬性;一個與清除緩存值二傳手:

class SomeFileType(object): 
    _filename = None 
    _client = None 

    def __init__(self, path): 
     self._path = path 

    @property 
    def path(self): 
     return self._path 

    @path.setter 
    def path(self, value): 
     # clear all private instance attributes 
     for key in [k for k in vars(self) if k[0] == '_']: 
      delattr(self, key) 
     self._path = value 

    @property 
    def filename(self): 
     if self._filename is None: 
      filename = os.path.basename(self.path) 
      self._filename = os.path.splitext(filename)[0] 
     return self._filename 

    @property 
    def client(self): 
     '''Returns client name associated with file''' 
     if self._client is None: 
      client = self.filename.split() 
      self._client = client[1] # Assuming filename is formatted "date client - docTitle" 
     return self._client 

因爲property基於緩存確實增加了一些複雜性的開銷,你需要考慮,如果真的是值得的;對於你的具體,簡單的例子,它可能不是。您的屬性的計算成本的確非常低,除非您計劃創建大量這些類,否則與必須維護按需緩存屬性的精神成本相比,提前計算屬性的開銷可以忽略不計。

+0

雖然此代碼當然有效,但我認爲如果將_filename = None移入__init__方法,而不是在屬性重寫之前保留類屬性,則會更加清楚。 – jlund3

+0

@ jlund3:爲什麼?這樣做絕對沒有意義。你也許可以完全刪除這個屬性,並且可以使用'if not hasattr(self,'_filename'):'而不是測試'如果self._filename是None:'但是在初始化器中將它設置爲'None'沒有任何用處。 '_filename'不被屬性覆蓋*。這個屬性被稱爲'filename',沒有下劃線,屬性設置一個實例屬性來緩存這個值。通過使它成爲一個類屬性,我們簡化了測試,如果緩存已經設置好了,並且*另外保存空間*。 –

+2

+1,用於在'__init__'方法之外執行'_filename = None'。從來沒有見過這種特殊的習語。 :) – Aya

5

你的代碼是做兩個不同的東西:

a)簡化通過暴露某些計算的屬性變量,而不是函數的類的API。

b)預計算它們的值。

第一個任務是屬性是什麼;一個簡單的使用將使你的代碼更簡單,而不是更復雜,(同樣重要)將使意圖更加清晰:

class someFileType(object): 
    @property 
    def filename(self): 
     return os.path.basename(self.path) 

然後,您可以編寫var.filename,你會動態計算從路徑的文件名。

@ Martijn的解決方案增加了緩存,同時也負責b部分(預計算)。在你的例子中,至少,計算結果很便宜,所以我沒有看到這樣做的好處。

相反,緩存或預計算引起一致性問題。考慮以下片段:

something = someFileType("/home/me/document.txt") 
print something.filename # prints `document` 
... 
something.path = "/home/me/document-v2.txt" 
print something.filename # STILL prints `document` if you cache values 

最後一條語句應該打印什麼?如果你緩存你的計算,你仍然會得到document而不是document-v2除非你是某些沒有人會嘗試更改基本變量的值,否則需要避免緩存或採取措施確保一致性。最簡單的方法是禁止修改path - 那性質designed to do.

結論的事情之一:使用屬性來簡化你的界面。不要緩存計算,除非由於性能原因而需要這些計算。如果你緩存,採取措施確保一致性,例如通過使底層值爲只讀。

PS。這些問題類似於數據庫規範化(非規範化設計引發一致性問題),但是在Python中,您有更多的資源來保持同步。

+0

正如注意:如果類正確寫入,那麼對something.path的賦值會使緩存的文件名失效,並在下次請求時觸發重新計算。 – cwallenpoole

+1

對,這是完全禁止修改的替代方法。但是它需要爲'path'定義一個setter(它將清空所有計算的值)或者(對於較重的應用程序)設置一個標誌或時間戳並在每次訪問計算值時檢查它。更重要的是,它需要時間,思考和調試才能做到正確。 「如果它寫得恰到好處」是神奇的話。 – alexis

+0

緩存值通常會。 – cwallenpoole