2009-11-10 22 views
4

在問題How do I "cd" in python中,接受的答案建議在類中包裝os.chdir調用,以便返回到原始目錄異常安全。這裏是推薦的代碼:如何在類中包裝不安全的python方法(例如os.chdir)使其線程/異常安全?

class Chdir:   
    def __init__(self, newPath): 
    self.savedPath = os.getcwd() 
    os.chdir(newPath) 

    def __del__(self): 
    os.chdir(self.savedPath) 

有人可以詳細說明這是如何工作,使不安全的調用異常安全嗎?

回答

7

線程安全性和異常安全性根本不是一回事。在這樣的班級中召喚os.chdir呼叫是爲了使其異常安全不是線程安全的

異常安全是您經常會聽到的C++開發人員所討論的內容。它在Python社區中幾乎沒有被討論過。從Boost的Exception-Safety in Generic Components文件:

通俗地說,在 成分異常安全意味着它具有 合理行爲異常時 在執行過程中被拋出。對於 大多數人來說,「合理」一詞 包含了所有的錯誤處理通常預期 :資源 不應該被泄露,那 程序應保持在 定義良好的狀態,以便執行 可以繼續。

因此,您提供的代碼片段中的想法是爲了確保在發生異常的情況下,程序將返回到定義明確的狀態。在這種情況下,進程將返回到它所啓動的目錄中,無論os.chdir本身是否失敗,或者導致拋出異常並刪除「Chdir」實例。

這種使用僅用於清理的對象的模式是「Resource Acquisition Is Initialization」或「RAII」的一種形式。該技術是在C++中很流行,但在Python中並不是如此受歡迎的幾個原因:

  • Python有try ...... finally,供應幾乎相同的目的,是在Python更常見的成語。
  • Python中的析構函數(__del__)在某些實現中不可靠/不可預知,因此以某種方式使用它們有點令人沮喪。在cpython中,只要不涉及循環(即:當刪除由引用計數處理),但在其他實現中(Jython和我相信IronPython)刪除發生在垃圾收集器周圍時,它們恰好是非常可靠且可預測的它可能會晚得多。 (有趣的是,這並不妨礙大多數Python程序員依靠__del__來關閉它們的打開文件。)
  • Python有垃圾回收,所以你不需要像在C++中那樣小心地進行清理。 (我不是說你不必須要小心可言,只是在普通情況下,你可以依靠GC做正確的事你。)

更「Python化」的方式寫上面的代碼將是:

saved_path = os.getcwd() 
os.chdir(new_path) 
try: 
    # code that does stuff in new_path goes here 
finally: 
    os.chdir(saved_path) 
+0

感謝勞倫斯。非常徹底和清晰。 – zlovelady 2009-11-10 18:38:47

+0

使用with語句更好(Python 2.5+) – compie 2011-08-17 15:05:18

1

__del__當實例即將銷燬時調用。所以當你實例化這個類時,當前工作目錄被保存到一個實例屬性中,然後調用os.chdir。當實例被銷燬時(無論出於何種原因),當前目錄被更改爲舊值。

這看起來有點不正確。據我所知,你必須電話父母__del__在你重寫__del__,所以應該更多這樣的:

class Chdir(object):   
    def __init__(self, new_path): 
    self.saved_path = os.getcwd() 
    os.chdir(new_path) 

    def __del__(self): 
    os.chdir(self.saved_path) 
    super(Chdir, self).__del__() 

也就是說,除非我失去了一些東西,當然。

(順便說一句,你能不能做到使用contextmanager一樣嗎?)

-2

僅此代碼是線程安全的,也沒有異常安全。其實我並不確定你的意思是異常安全。下面的代碼想到:

try: 
    # something thrilling 
except: 
    pass 

這是一個可怕的想法。例外不是防範。寫得好的代碼應該是catch exceptions,並對它們做一些有用的事情。

+1

我認爲「異常安全」,他的意思如下:「即使失去控制因異常被提出,我們都保證恢復到原來的目錄」 。 – shylent 2009-11-10 17:49:32

+0

有趣的是,你說它不是例外的安全,然後承認你不知道什麼是異常安全的手段。 – 2009-11-10 18:01:01

+0

無論什麼異常安全的手段;你能說「單獨的代碼是異常安全的嗎?」?通過代碼我的意思是在問題中的Chdir類。 – muhuk 2009-11-10 18:21:48

5

問題的直接答案是:它沒有,發佈的代碼是可怕的。

像下面可能是合理的,使之「異常安全」(但更好的是要避免的chdir和使用完整路徑來代替):

saved_path = os.getcwd() 
    try: 
    os.chdir(newPath) 
    do_work() 
    finally: 
    os.chdir(saved_path) 

而這個精確的行爲也可以寫進情境管理器。

+0

'os.chdir(newPath)'可能不應該放在'try'語句中 - 如果失敗,當前工作目錄沒有改變,所以不需要重置它。 (在這種情況下,它是無害的,因爲'os.chdir(os.getcwd())'是一個無操作,但如果'saved_pa​​th'是相對的,這將是麻煩) – Thomas 2014-08-12 04:26:06