2014-07-22 86 views
2

看來,對象清理是我在編程日期間遇到的一個非常常見的問題。迄今爲止,我一直使用with陳述作爲建議hereTry-finally修飾器清理python對象

我今天有另一個想法,這似乎對我更優雅(因爲它不需要由最終用戶的聲明)。這個想法是爲某種類型的對象使用try-finally修飾器(具有清理方法)。

只是想知道這種做法是否有什麼問題,或者如果有什麼更好的。我不喜歡我的許多類需要使用with語句進行初始化,但我也想確保我的對象正確關閉。這是一個簡短的例子。

def cleanme(func): 
    def _decorator(self, *args, **kwargs): 
     try: 
      func(self, *args, **kwargs) 
     finally: 
      self._cleanup() 

    return _decorator 


class IObject(object): 
    def __init__(self): 
     self.file_name = "some_file.txt" 
     self._file_object = None 
     self._cleaned = True 

    @cleanme 
    def run(self): 
     self._connect() 
     while True: 
      # do some things over a long period 
      pass 

    def _connect(self): 
     self._file_object = open(self.file_name) 
     self._cleaned = False 

    def _cleanup(self): 
     if not self._cleaned: 
      self._file_object.close() 
      self._cleaned = True 
+1

「與」的意思是擺脫這種「清理以後的所有事情」的想法,並明確指出您使用的資源。你應該把你的對象分爲兩部分,一部分是資源(保存那個文件對象並且知道如何清理),另一部分是使用它的,'run'方法應該是'with my_resources:while True:do_stuff() 」。 –

+0

使用多個IO樣式對象時會變得非常混亂(比如我有3個插槽可以接收數據,視頻輸入對象和一些通信管道等)。相反,我可以只有一個連接方法和一個處理每一個的close方法。 –

+2

我想這處理該問題:http://stackoverflow.com/questions/3024925/python-create-a-with-block-on-several-context-managers –

回答

2

讓我在這裏拍幾個洞。

一個想法是,你要求你的班級有一個cleanup(),這是宣佈不在run()不同的地方。所以你強加一個用戶的責任來實現和保持乾淨。

除了__exit__之外的其他析構函數在Python中很少見,所以資源獲取代碼可能會從cleanup()代碼中漂移,造成泄漏。

其次,你使file_object成爲一個實例變量,從而擴大了它的範圍,從一個單一的函數,這也有點不好。

2

我覺得這個方法是好的,只要你的客戶端將只使用您IOObject做任何run做,而不會想直接調用connect,然後使用該得到打開file_object做一些其他的操作。

上下文管理器使客戶可以很容易地知道他們正在獲取/清理資源的位置,還可以讓他們靈活地實現他們想要的任何事情,知道只要他們離開with阻止它將被清理。採用這種方法不太清楚;客戶需要查看代碼(或者文檔)以知道run方法會爲他們清理,但如果直接使用connect,則需要調用cleanup以正確清理。

還有Python的規則規則「Excplicit比Implicit好」。語句with明確地顯示正在獲取和釋放資源的客戶端。你用裝飾者的方法失去了這一點。