Sì, The Zen of Python afferma "L'appartamento è migliore di quello annidato", tuttavia non è l'unica caratteristica che ci interessa; afferma anche "Semplice è meglio che complesso". La bellezza di with
è che in realtà rispetta lo di entrambi i principi, come spiegherò di seguito.
Ogni volta che ti ritrovi a riflettere filosoficamente su una funzione in Python, probabilmente vale la pena consultare lo Python Enhancement Proposals (PEPs) per leggere la motivazione alla base della funzionalità. In questo caso PEP 343 -- The "with" Statement dice che in attacco in astratto:
Questa PEP aggiunge una nuova dichiarazione "con" al linguaggio Python per renderlo possibile scomporre usi standard di try/finally dichiarazioni.
Il factoring delle dichiarazioni try/finally
semplifica e rende più leggibile il codice.
PEP 343 va più in profondità che fornire uno zucchero sintattico semplicistico, tuttavia. Si stabilisce un protocollo contesto manager:
L'espressione che segue immediatamente la con parola chiave nella dichiarazione è un "espressione contesto" come quella espressione fornisce l'indizio principale per l'ambiente di runtime manager contesto stabilisce per la durata del corpo della dichiarazione.
Utilizzando il protocollo di gestione del contesto, gli autori di API possono aiutare a nascondere la complessità e garantire la corretta acquisizione/rilascio di risorse in un contesto multi-thread.
Ma la vera bellezza della dichiarazione with
è mostrato nell'esempio 12 del PEP 343 che spiega che:
Un manager contesto "annidata" che nidifica automaticamente i forniti contesti da sinistra a destra per evitare indentazione eccessiva.
Utilizzando il manager nested()
contesto si può prendere il codice che assomiglia a questo:
with a as x:
with b as y:
with c as z:
# Perform operation
e trasformarlo in questo:
with nested(a, b, c) as (x, y, z):
# Perform operation
Nota che nested()
è stato introdotto in Python 2.5, ma a partire dalla versione 2.7 è deprecato a favore di questo modulo sintattico di gestione contesto multiplo:
with a as x, b as y, c as z:
# Perform operation
Chiaramente non solo è più semplice e più leggibile, ma è molto più piatto di quello annidato. Così, utilizzando with
è seguendo il percorso di 無爲 :)
UPDATE: In risposta a comments on Simeon Visser's answer qui è un esempio di quando si potrebbe utilizzare più gestori di contesto di aprire più di un file alla volta, quando si desidera zip il contenuto di due (o più) file insieme tale che se l'apertura di uno dei file fallisce renderà il tutto fallire e chiudere correttamente ogni file che è stato aperto:
from itertools import izip
with open("/etc/passwd") as a, open("/etc/group") as b, open("/etc/shadow") as c:
for lines in izip(a,b,c):
print map(lambda x: x.split(':')[0], lines)
Esegui questo esempio due volte; una volta come root e una volta come utente normale. Supponendo di salvare questo file come ziptogether.py
, provare prima a chiamarlo come root con sudo python ziptogether.py
e ci riuscirà, ma il richiamo come utente normale con python ziptogether.py
avrà esito negativo perché non si dispone delle autorizzazioni per leggere /etc/shadow
. Quando fallisce, il gestore di contesto si assicura che i file che sono stati aperti correttamente prima dell'errore vengano chiusi correttamente quando l'esecuzione si sposta al di fuori dell'ambito dell'istruzione with
.
La maggior parte delle volte lascio IOError propagarsi e catturarlo da qualche altra parte. – Dikei
Per quanto non sia d'accordo con la premessa di questa domanda, devo darti degli oggetti di scena per farmi tornare indietro e rileggere PEP [342] (http: //www.python.org/dev/peps/pep-0342 /) e [343] (http://www.python.org/dev/peps/pep-0343/) – kojiro