2014-10-28 17 views
6

dosyaların kapanış okudum, bu dosya otomatik olarak kapatılır böyle açtı:ve Python

from contextlib import closing 
from urllib.request import urlopen 

with closing(urlopen('http://www.python.org')) as page: 
    for line in page: 
     print(line) 
:

with open("x.txt") as f: 
    data = f.read() 
    do something with data 

henüz web'den açarken, buna ihtiyacım var

neden ve fark nedir? (Python3 kullanıyorum)

+0

Birinin bunun için 'contextlib' üzerinde bir dosya hatası vermesi gerektiğini ve bunun için her kimsenin size kredi vermemesi gerektiğini söylemeyi düşünmek üzereydim ... ama bitiremeden önce, Martijn zaten bir hata yaptı buraya. :) – abarnert

cevap

6

ayrıntıları biraz teknik olsun, bu yüzden basit sürümü ile başlayalım:

Bazı türleri bir with açıklamada kullanılacak biliyorum. open'dan geri aldığınız şeyler gibi dosya nesneleri, böyle bir örnektir. Sonuç olarak, urllib.request.urlopen'dan geri döndüğünüz nesneler da türünde bir örnektir, böylece ikinci örneğiniz ilk ile aynı şekilde yazılabilir.

Bazı türler, bir with deyiminde nasıl kullanılacağını bilmez.closing işlevi, close yöntemine sahip oldukları sürece, with deyiminden çıktığınızda close yöntemini çağırır. Onların temizleme yöntemi close adında (ya da değil, çünkü bazı türleri de bir with açıklamada kullanılacak bilen ve yok Tabii

closing ile kullanılamaz onları temizlemeye sadece daha karmaşıktır çünkü onları kapatarak). Bu durumda, özel bir içerik yöneticisi yazmanız gerekir. Ama bu bile o kadar da zor değil. Teknik açıdan


:

A with açıklamada bir context manager, __enter__ ve __exit__ yöntemlerle bir nesne gerektirir. __enter__ yöntemini çağırır ve as deyiminde bu yöntem tarafından döndürülen değeri verir ve with ifadesinin sonunda __exit__ yöntemini çağırır.

dosya nesneleri __exit__ aramalar self.close() bir bağlam __enter__ yöntem, kendisi ile döner Yöneticisi ve bir io.IOBase devralır.

urlopen tarafından döndürülen nesne dokümanlar söylediği gibi, "Bir with deyimi ile kullanılabilir", bir HTTPResponse, (bir http veya https URL varsayarak) 'dir.

closing fonksiyonu:

geri bloğunun tamamlanması üzerine bir şey kapatan bir bağlam yöneticisi. Bu temelde eşdeğerdir:

@contextmanager 
def closing(thing): 
    try: 
     yield thing 
    finally: 
     thing.close() 

It türleri bağlam yöneticileri ve türleri değildir dokümanlarında her zaman% 100 net. Özellikle 3.1'den beri büyük bir sürücü olduğu için, bir içerik yöneticisi haline getirilebilecek her şeyi (ve bu nedenle, çoğunlukla dosya-benzeri-gibi bir şeyleri gerçek bir IOBase'a dönüştürmek) yapmak, ancak hala değil % 100'ü 3,4 olarak tamamlandı.

Her zaman deneyebilir ve görebilirsiniz. Bir AttributeError: __exit__ alırsanız, nesne bir içerik yöneticisi olarak kullanılamaz. Olması gerektiğini düşünüyorsanız, değişikliği öneren bir hata gönderin. Bu hatayı almazsanız, ancak dokümanlar yasal olduğunu belirtmezse, dokümanların güncellenmesini öneren bir hata oluşturur.

+0

detaylı açıklama için teşekkürler! – nekomimi

7

Yapmıyorsunuz. urlopen('http://www.python.org') döner de bir bağlam yöneticisi: Bu urllib.request.urlopen() page belgelendirdikten

with urlopen('http://www.python.org') as page: 

:

ftp, dosya ve veri url'lerin

ve mirası URLopener ve FancyURLopener sınıflar tarafından ele explicity, bu işlev bir döner istekleri içerik yöneticisi olarak çalışabilen urllib.response.addinfourl nesnesi [...].

Vurgulamak benim.

yanıtı bir iterable amacı ve deyimi ile kullanılabilir: http yanıt için http.client.HTTPResponse() object da bağlam yöneticisi olan döndürülür. meta etiketi, biz bayt kodunu çözmek için aynı kullanacaktır oluyor buna belirtilen python.org web utf-8 kodlaması kullanır gibi

:

Examples section

da bir bağlam yöneticisi olarak nesnesi kullanır nesne. open() tarafından döndürülen

>>> with urllib.request.urlopen('http://www.python.org/') as f: 
...  print(f.read(100).decode('utf-8')) 
... 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtm 

nesneler çok context managers vardır; Özel yöntemleri object.__enter__() ve object.__exit__() uygularlar.

contextlib.closing() documentation, güncel olmayan urlopen() numaralı bir örneği kullanır; Python 2'de urllib.request.urlopen() için öncül bir içerik yöneticisi üretmedi ve bu aracı bir bağlam yöneticisi ile otomatik olarak kapatmak için kullanmanız gerekiyordu. Bu, 5418 ve 12365 sorunları ile düzeltildi, ancak bu örnek güncelleştirilmedi. Farklı bir örnek için issue 22755'u oluşturdum.

+0

Ben sadece bu :-) yazmak üzereydim. Anahtar, belgelerin "dosyaya benzer" bir nesne döndürdüğü şeklindedir. İçerik yöneticisi olarak kullanılamazsa, aslında dosya benzeri değil. – mgilson

+0

ama bu örnek python dokümanlarında neden o zaman? https://docs.python.org/3/library/contextlib.html – nekomimi

+1

@nekomimi: nesnenin bir içerik yöneticisi olmadığı muhtemelen Python 2'den bir görevli. –