Variabel ditentukan dengan pernyataan dengan tersedia di luar blok dengan?

90

Perhatikan contoh berikut:

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

Saya telah membaca dokumen bahasa (2.7) untuk with-statement serta PEP-343, tetapi sejauh yang saya tahu mereka tidak mengatakan apa-apa tentang masalah ini.

Dalam CPython 2.6.5 ftampaknya didefinisikan di luar blok with, tetapi saya lebih suka tidak bergantung pada detail implementasi yang dapat berubah.

Heikki Toivonen
sumber
8
Pertanyaan apakah f akan tersedia atau tidak dalam lingkup terlampir sudah terjawab. Bagi saya, seluruh konsep manajer konteks menjadi klik ketika saya menyadari bahwa konsep konteks berbeda dengan ruang lingkup . Berikut ini tautan ke situs web saya yang semoga membantu sedikit: markus-gattol.name/ws/python.html#context_manager
Tom
1
Persis - konteksnya adalah masalah mengubah status saat ini - file terbuka, file ditutup atau utas terkunci / tidak terkunci. Perangkat dialokasikan / dibatalkan alokasinya. Semua variabel yang disebutkan dalam scope masih ada - tetapi sekarang mereka akan mengarah ke pegangan yang tidak dialokasikan / ditutup / tidak terkunci.
Danny Staple

Jawaban:

159

Ya, manajer konteks akan tersedia di luar pernyataan with dan itu tidak tergantung pada implementasi atau versi. dengan pernyataan tidak membuat ruang lingkup eksekusi baru.

fuzzyman
sumber
3
Ini adalah penjelasan paling jelas menurut saya sehingga memberikan jawaban yang diterima; akan memberikan poin kepada Alex dan TokenMacGuy untuk info tambahan yang berguna.
Heikki Toivonen
Sesuatu yang dapat dengan mudah dilupakan jika tidak bekerja dengan Python untuk sementara waktu, fungsi seperti indentasi, nama dan hal-hal lain menyarankan bahwa Anda seharusnya tidak dapat mengaksesnya dan Anda masih bisa.
Vitaliy Terziev
28

yang withsintaks:

with foo as bar:
    baz()

kira-kira gula untuk:

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

Ini seringkali berguna. Sebagai contoh

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

with myLock:
    frob_some_more()

manajer konteks mungkin berguna lebih dari sekali.

SingleNegationElimination
sumber
Yah, penggunaan kembali kunci mungkin atau mungkin tidak (tidak tahu, tetapi akan menjadi bug jika mereka berbeda) - tetapi aturan pelingkupan Python pasti akan sama di sini di seluruh implementasi.
fuzzyman
1
sekali lagi ini bukan masalah pelingkupan. Cakupannya akan sama. Namun, jika implementasi dari foo .__ exit__ menempatkan utas ke status berhenti, kecuali jika kunci memiliki enter yang menguncinya kembali, pernyataan kedua sepertinya tidak akan berguna untuk kunci utas.
Danny Staple
16

Dalam kasus ffile, itu akan muncul ditutup di luar withpernyataan.

Misalnya, ini

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

akan mencetak:

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

Anda dapat menemukan detailnya di PEP-0343 di bawah bagian Spesifikasi: Pernyataan 'dengan' . Aturan lingkup Python (yang mungkin menjengkelkan ) berlaku fjuga.

miku
sumber
Saya tahu ini, saya sebutkan dalam pertanyaan. Setidaknya untuk CPython 2.6.5. Tetapi dapatkah Anda menjamin bahwa hal yang sama berlaku untuk Jython, IronPython, dan PyPy?
Heikki Toivonen
Aturan cakupan Python juga tidak selalu jelas. Pertimbangkan ini di CPython 2.6.5: [x for x in [1]]. xtersedia di luar itu. Membuatnya menjadi generator: (x for x in [1]). Sekarang xtidak tersedia. Sepertinya saya ingat ini diubah dalam Python 3 sehingga bahkan dengan pemahaman daftar xtidak akan bocor, tetapi saya tidak dapat menemukan referensi sekarang.
Heikki Toivonen
Saya mencari, tapi belum menemukan sesuatu yang penting untuk saat ini. Pertanyaan yang menarik.
miku
Sebenarnya ini bukan masalah lingkup - variabel f ​​masih tersedia, tetapi sekarang menangani file dalam keadaan tertutup - file yang sama yang sebelumnya dibuka sebelumnya. Panggilan keluar ketika konteksnya dibiarkan akan mengubah keadaan ini.
Danny Staple
11

Untuk menjawab pertanyaan Heikki di komentar: ya, perilaku pelingkupan ini adalah bagian dari spesifikasi bahasa python dan akan berfungsi pada semua dan semua Pythons yang sesuai (yang mencakup PyPy, Jython, dan IronPython).

Alex Gaynor
sumber