Variabile definita con istruzione with disponibile al di fuori di with-block?


88

Considera il seguente esempio:

with open('a.txt') as f:
    pass
# Is f supposed to be defined here?

Ho letto i documenti in lingua (2.7) sia per with-statement che per PEP-343, ma per quanto ne so non dicono nulla su questo argomento.

In CPython 2.6.5 fsembra essere definito al di fuori del with-block, ma preferisco non fare affidamento su un dettaglio di implementazione che potrebbe cambiare.


8
La domanda se f sarebbe disponibile o meno nell'ambito di applicazione allegato è già stata risolta. Per me l'intero concetto di gestori di contesto è scattato quando ho capito che il concetto di contesto è diverso da quello di ambito . Ecco un collegamento al mio sito Web che si spera aiuti un po ': markus-gattol.name/ws/python.html#context_manager
Tom,

1
Esatto: un contesto è una questione di cambiamento dello stato corrente: file aperto, file chiuso o thread bloccato / sbloccato. Dispositivo assegnato / deallocato. Tutte le variabili denominate nell'ambito sono ancora presenti, ma ora punteranno a handle deallocati / chiusi / sbloccati.
Danny Staple

Risposte:


158

Sì, il gestore del contesto sarà disponibile al di fuori dell'istruzione with e non dipende dall'implementazione o dalla versione. with le istruzioni non creano un nuovo ambito di esecuzione.


3
Questa è la spiegazione più chiara a mio parere che premia la risposta accettata; darà punti ad Alex e TokenMacGuy per ulteriori informazioni utili.
Heikki Toivonen

Qualcosa che si potrebbe facilmente dimenticare se non si lavora con Python per un po ', la funzione come indentazione, nome e cose suggerisce che non dovresti essere in grado di accedervi e tuttavia puoi.
Vitaliy Terziev

28

la withsintassi:

with foo as bar:
    baz()

è approssimativamente zucchero per:

try:
    bar = foo.__enter__()
    baz()
finally:
    if foo.__exit__(*sys.exc_info()) and sys.exc_info():
        raise

Questo è spesso utile. Per esempio

import threading
with threading.Lock() as myLock:
    frob()

with myLock:
    frob_some_more()

il gestore di contesto può essere utile più di una volta.


Bene, il riutilizzo del blocco può o non può (non ne ho idea, ma sarebbe un bug se fossero diversi) - ma le regole di scoping di Python saranno sicuramente le stesse in tutte le implementazioni.
fuzzyman

1
anche questo non è un problema di scoping. Lo scoping sarà lo stesso. Tuttavia, se l'implementazione di mette foo .__ exit__ il filo in uno stato fermato, quindi a meno che non ha un blocco entrare che riblocca essa, la seconda istruzione non sembra che avrebbe fatto qualcosa di utile per le serrature filo.
Danny Staple

16

Nel caso in cui fsia un file, apparirà chiuso al di fuori withdell'istruzione.

Ad esempio, questo

f = 42
print f
with open('6432134.py') as f:
    print f
print f

stamperà:

42
<open file '6432134.py', mode 'r' at 0x10050fb70>
<closed file '6432134.py', mode 'r' at 0x10050fb70>

È possibile trovare i dettagli in PEP-0343 nella sezione Specifiche: l'istruzione "with" . Anche le regole di ambito Python (che potrebbero essere irritanti ) si applicano f.


Lo so, l'ho menzionato nella domanda. Almeno per CPython 2.6.5. Ma puoi garantire che lo stesso vale per Jython, IronPython e PyPy?
Heikki Toivonen

Anche le regole di ambito di Python non sono sempre così chiare. Considerate questo in CPython 2.6.5: [x for x in [1]]. xè disponibile al di fuori di quello. Ne fanno in un generatore: (x for x in [1]). Ora xnon è disponibile. Mi sembra di ricordare che questo è stato cambiato in Python 3 in modo che anche con la comprensione dell'elenco xnon trapelasse, ma non riesco a trovare il riferimento ora.
Heikki Toivonen

Ho cercato, ma per ora non ho trovato nulla di significativo. Domanda interessante, però.
miku

In realtà questa non è una questione di ambito - la variabile f è ancora disponibile, ma ora è un handle per il file nello stato chiuso - lo stesso file che era precedentemente aperto. La chiamata di uscita quando il contesto viene lasciato cambierà questo stato.
Danny Staple

11

Per rispondere alla domanda di Heikki nei commenti: sì, questo comportamento di scoping fa parte delle specifiche del linguaggio Python e funzionerà su tutti i Pythons conformi (che includono PyPy, Jython e IronPython).

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.