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.