這是我認爲必須經常提出的事情,但我一直無法找到一個好的解決方案。假設我有一個函數可以傳遞一個開放資源作爲參數(如文件或數據庫連接對象)或需要自己創建一個。如果函數需要打開自己的文件,最好的做法通常被認爲是這樣的:Pythonic方式有條件地使用上下文管理器
with open(myfile) as fh:
# do stuff with open file handle...
以確保文件時with
退出塊總是關閉。但是,如果在函數中傳遞一個現有的文件句柄,它可能本身不應該關閉它。
請考慮以下函數,它可以使用打開的文件對象或將文件路徑作爲參數的字符串。如果它通過一個文件路徑,它應該可以像上面那樣編寫。否則with
聲明應該被省略。這導致重複代碼:
def foo(f):
if isinstance(f, basestring):
# Path to file, need to open
with open(f) as fh:
# do stuff with fh...
else:
# Assume open file
fh = f
# do the same stuff...
這當然可以通過定義一個輔助函數,把它在這兩個地方是可以避免的,但是這看起來不太優雅。一個更好的辦法,我認爲是定義一個包裝就像一個對象,上下文管理類:
class ContextWrapper(object):
def __init__(self, wrapped):
self.wrapped = wrapped
def __enter__(self):
return self.wrapped
def __exit__(self, *args):
pass
def foo(f):
if isinstance(f, basestring):
cm = open(f)
else:
cm = ContextWrapper(f)
with cm as fh:
# do stuff with fh...
這工作,但除非有一個內置的對象,它這個(我不認爲這是)我要麼隨處複製粘貼該對象,要麼必須導入我的自定義實用程序模塊。我覺得有一個更簡單的方法可以做到這一點,我錯過了。
我想不出一個很好的理由來編寫代碼,將接受* *任意路徑*或*打開文件句柄。在這種邊緣情況下,我建議編寫自己的包裝(正如你所做的那樣) –
我認爲輔助函數可能更優雅。你在'foo'中做的很多工作是將參數放到正確類型的對象中 - 一個打開的文件句柄。將執行核心工作的代碼分解爲一個假定打開文件句柄的助手,我認爲總體結果更清晰。實際上,「助手」本身可能是一個合法的公共函數,「foo_from_path」在打開文件處理程序後只是簡單地調用「foo」。 – jme
@AdamSmith對於它的價值,這是一種常見的設計,比如numpy。例如,'np.load'採用[string或者fileobj](http://docs.scipy.org/doc/numpy-1.10.1/reference/generated/numpy.load.html)。我想這只是爲了讓一些代碼更加簡潔,而且因爲numpy經常被交互使用,所以這不是不明智的做法。 – jme