2012-03-25 58 views
4

我明白why contextlib.nested is deprecated解決方法怪癖在contextlib.nested

但是,如果我編寫一箇舊的Python版本的W/O與多種形式(即,< 2.7)的程序,我(幾乎)沒有其他選擇。

爲了避免下面的結構失敗:

with nested(open("f1"), open("f2")) as (f1, f2): 

f1如果開放f2失敗不會關,因爲沒有進入contextmanager)

我能想象寫上下文管理器,它初始化移動到其__enter__

@contextmanager 
def late_init(f, *a, **k): 
    r = f(*a, **k) 
    with r as c: yield c 

我說得對不對THI nking是

with nested(late_init(open, "f1"), late_init(open, "f2")) as (f1, f2): 

將在這裏足以讓 「乾淨」?


給出的用例僅僅是一個例子。想象一下,你有一個文件的列表,其長度不會過早知道。然後既不2.7組成with是可用的,也不符合幾個縮進with語句預2.7嵌套方式。


我可能必須對此更詳細。

上述worharound乍一看解決了問題:調用函數在一個安全的地方執行,以便可以檢測到故障並進行適當處理。

我的問題是:它是否治癒的缺陷,還是我讓其他的問題?

回答

1

我現在看到我的解決方案(late_init())可能會固化第一怪癖:

首先,作爲背景的經理都在調用 功能之前建造的,上下文管理器的__new__()__init__()方法實際上並未被上下文管理器的範圍覆蓋。這意味着,例如,使用nested()打開 兩個文件是一個編程錯誤,因爲如果打開第二個文件時引發異常,第一個文件將不會立即關閉 。

但第二之一:

其次,如果內上下文 經理之一的__enter__()方法引發由所述外上下文中的一個的 __exit__()方法捕獲並抑制異常經理,這個構造會引發RuntimeError,而不是跳過 聲明的正文。

(這可能是由跳過的yield varsnested()引起的)不包括在內。

因此,要麼

  1. 應避免在組合使用「異常食」與nested()
  2. 給定nested()應具有更好的一個或
  3. 使用可變長度的異常來代替應該避免使用經理名單,以及舊的Python版本。
3

contextlib.nested工具用於將上下文管理器組合爲一個。它被棄用,因爲它有設計上的缺陷(對於你已經顯示的情況,f1將不會被關閉,如果打開f2失敗)。

您使用情況下不需要成分雖然。經常築巢就足夠了:

with open('f1') as f1: 
    with open('f2') as f2: 
     ... 
+0

是的,我已經說過了。但是這個答案並沒有真正回答我的問題。想象一下,我沒有2個文件,但5或10或者我有一個可變長度文件的列表/元組。在這種情況下,您的解決方案並不可行。 – glglgl 2012-03-25 13:35:10