With-ifadesiyle tanımlanmış değişken with-block dışında kullanılabilir mi?


90

Aşağıdaki örneği düşünün:

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

PEP-343'ün yanı sıra with-statement için dil belgelerini (2.7) okudum, ancak söyleyebileceğim kadarıyla bu konuda hiçbir şey söylemiyorlar.

CPython 2.6.5'te f, bloklu bloğun dışında tanımlanmış gibi görünüyor, ancak değişebilecek bir uygulama ayrıntısına güvenmeyi tercih etmiyorum.


8
F'nin ekli kapsamda bulunup bulunmayacağı sorusu zaten yanıtlanmıştır. Bir kavramı olduğunu fark edince Benim için bağlam yöneticilerinin bütün kavramı tıklanan bağlam yazıdan farklı olan kapsam . İşte web siteme biraz yardımcı olacağını umduğum bir bağlantı: markus-gattol.name/ws/python.html#context_manager
Tom

1
Kesinlikle - bağlam, mevcut durumu değiştirme meselesidir - dosya açık, dosya kapalı veya iş parçacığı kilitli / kilidi açıldı. Cihaz tahsis edildi / serbest bırakıldı. Kapsamda adlandırılan tüm değişkenler hala oradadır - ancak artık ayrılmamış / kapatılmış / kilitli olmayan tutamaçları göstereceklerdir.
Danny Staple

Yanıtlar:


160

Evet, içerik yöneticisi with ifadesinin dışında mevcut olacak ve bu uygulama veya sürüme bağlı değil. ifadeleriyle yok yeni bir yürütme kapsamını oluşturmak.


3
Bu bence en net açıklama, bu yüzden kabul edilen cevabı ödüllendiriyorum; ek yararlı bilgiler için Alex ve TokenMacGuy'a puan verecektir.
Heikki Toivonen

Python ile bir süredir çalışmadıysa kolayca unutulabilecek bir şey, girinti, isim ve diğer şeyler gibi işlev, ona erişememeniz gerektiğini ve yine de yapabileceğinizi gösterir.
Vitaliy Terziev

28

withsözdizimi:

with foo as bar:
    baz()

yaklaşık olarak şekerdir:

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

Bu genellikle faydalıdır. Örneğin

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

with myLock:
    frob_some_more()

bağlam yöneticisi birden fazla kullanımda olabilir.


Pekala, kilit yeniden kullanımı olabilir veya olmayabilir (fikir yok, ancak farklı olsaydı bir hata olurdu) - ancak Python kapsam belirleme kuralları burada uygulamalarda kesinlikle aynı olacaktır.
fuzzyman

1
bu yine bir kapsam sorunu değildir. Kapsam aynı olacaktır. Foo .__ exit__ koyar uygulaması içine iplik durumuna durursa kilit olmadıkça Ancak, daha sonra bir girip o iplik kilitleri işe yarar bir şey yapacağını gibi o tekrar kilitler bunu, ikinci ifade görünmüyor.
Danny Staple

16

fDosya olması durumunda , withifadenin dışında kapalı görünecektir .

Örneğin, bu

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

yazdıracaktı:

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

Ayrıntıları PEP-0343'te Specification: The 'with' ifadesi altında bulabilirsiniz . Python kapsam kuralları ( rahatsız edici olabilir ) için fde geçerlidir .


Bunu biliyorum, soruda bundan bahsetmiştim. En azından CPython 2.6.5 için. Ancak bunun Jython, IronPython ve PyPy için de geçerli olduğunu garanti edebilir misiniz?
Heikki Toivonen

Python'un kapsam kuralları da her zaman o kadar net değildir. CPython 2.6.5 bu düşünün: [x for x in [1]]. xbunun dışında mevcuttur. Bir jeneratör haline Make: (x for x in [1]). Şimdi xmevcut değil. Python 3'te bunun değiştiğini hatırlıyorum, böylece liste kavrayışıyla bile xsızmaz, ancak referansı şimdi bulamıyorum.
Heikki Toivonen

Aradım, ancak şimdilik önemli bir şey bulamadım. Yine de ilginç bir soru.
miku

Aslında bu bir kapsam meselesi değildir - f değişkeni hala kullanılabilir, ancak şimdi kapalı durumda dosyalama için bir tutamaçtır - daha önce açık olan aynı dosya. Bağlam bırakıldığında çıkış çağrısı bu durumu değiştirecektir.
Danny Staple

11

Heikki'nin yorumlarda sorusuna cevap vermek gerekirse: evet, bu kapsam belirleme davranışı python dil spesifikasyonunun bir parçasıdır ve tüm uyumlu Python'lar (PyPy, Jython ve IronPython dahil) üzerinde çalışacaktır.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.