Bir dosyanın tamamını okumak dosya tanıtıcısını açık bırakıyor mu?


372

İle tüm dosyayı okursanız content = open('Path/to/file', 'r').read(), komut dosyası çıkana kadar dosya tanıtıcısı açık bırakılır mı? Bir dosyayı okumak için daha özlü bir yöntem var mı?

Yanıtlar:


585

Bu sorunun cevabı bir şekilde belirli Python uygulamasına bağlıdır.

Bunun ne hakkında olduğunu anlamak için, gerçek filenesneye özellikle dikkat edin . Kodunuzda, bu nesne bir ifadede yalnızca bir kez bahsedilir ve read()çağrı döndükten hemen sonra erişilemez hale gelir .

Bu, dosya nesnesinin çöp olduğu anlamına gelir. Geriye kalan tek soru "Çöp toplayıcı dosya nesnesini ne zaman toplayacak?".

referans sayacı kullanan CPython'da bu tür çöpler hemen fark edilir ve bu yüzden derhal toplanır. Bu genellikle diğer python uygulamaları için geçerli değildir.

Dosyanın kapalı olduğundan emin olmak için daha iyi bir çözüm bu kalıptır:

with open('Path/to/file', 'r') as content_file:
    content = content_file.read()

blok bittikten hemen sonra dosyayı her zaman kapatacaktır; bir istisna olsa bile.

Düzenleme: Üzerine daha ince bir nokta koymak için:

Bunun dışında file.__exit__()"otomatik olarak" Bir de denir, withbağlam yöneticisi ayarı, sadece başka bir şekilde file.close()otomatik olarak adlandırılır (açıkça kendiniz çağırarak dışında olduğu,) yoluyladır file.__del__(). Bu bizi ne zaman __del__()çağrılır?

Doğru yazılmış bir program, kesinleştiricilerin program sonlandırılmadan önce herhangi bir noktada çalışacağını varsayamaz.

- https://devblogs.microsoft.com/oldnewthing/20100809-00/?p=13203

Özellikle:

Nesneler asla açıkça yok edilmez; ancak ulaşılamaz hale geldiklerinde çöp toplanabilirler. Bir uygulamanın çöp toplamayı ertelemesine veya tamamen atlamasına izin verilir - hala ulaşılabilen hiçbir nesne toplanmadıkça, çöp toplamasının nasıl uygulandığı bir uygulama kalitesidir.

[...]

CPython şu anda, çoğu nesneyi ulaşılamaz olur olmaz toplayan ancak dairesel referanslar içeren çöpleri toplaması garanti edilmeyen (isteğe bağlı), çevrimsel olarak bağlı çöplerin gecikmeli olarak algılanması ile bir referans sayma şeması kullanmaktadır.

- https://docs.python.org/3.5/reference/datamodel.html#objects-values-and-types

(Vurgu madeni)

ancak öne sürdüğü gibi, diğer uygulamaların başka davranışları olabilir. Bir örnek olarak, PyPy vardır 6 farklı çöp toplama uygulamalarını !


24
Bir süredir başka Python uygulamaları yoktu; ancak uygulama ayrıntılarına güvenmek aslında Pythonic değildir.
Karl Knechtel

Hala uygulamaya özel mi, yoksa zaten standartlaştırılmış mı? Bu __exit__()gibi durumlarda arama yapmamak bir tasarım kusuru gibi geliyor.
rr-

2
@jgmjgm Tam olarak bu 3 sorun, GC'nin öngörülemez olması try/ finallyhareketsiz olması ve withçözen temizleme işleyicilerinin oldukça yaygın kullanımı nedeniyle . "Açık bir şekilde kapanma" ile "yönetme" arasındaki fark with, bir istisna atılmış olsa bile çıkış işleyicisinin çağrılmasıdır. Bunu close()bir finallycümle içine koyabilirsiniz , ancak bunun withyerine kullanmaktan çok farklı değil, biraz daha karışık (1 yerine 3 ekstra satır) ve doğru elde etmek biraz daha zor.
SingleNegationElimination

1
Bu konuda elde edemediğim şey, 'açık' olmasının neden açık olmadığı için artık güvenilir olması. Çünkü spec her zaman böyle uygulanması gerektiğini söylüyor?
jgmjgm

3
daha güvenilir, çünkü bulunuyor @jgmjgm with foo() as f: [...]temelde aynıdır f = foo(), f.__enter__()[...] ve f.__exit__() ele istisnalar dışında , böylece __exit__her zaman denir. Böylece dosya her zaman kapanır.
neingeist

104

Pathlib kullanabilirsiniz .

Python 3.5 ve üstü için:

from pathlib import Path
contents = Path(file_path).read_text()

Python'un daha eski sürümleri için pathlib2'yi kullanın :

$ pip install pathlib2

Sonra:

from pathlib2 import Path
contents = Path(file_path).read_text()

Gerçek read_text uygulama budur :

def read_text(self, encoding=None, errors=None):
    """
    Open the file in text mode, read it, and close the file.
    """
    with self.open(mode='r', encoding=encoding, errors=errors) as f:
        return f.read()

2

Her satırla çalışmak için dosya satır satır okumak zorunda kalırsanız,

with open('Path/to/file', 'r') as f:
    s = f.readline()
    while s:
        # do whatever you want to
        s = f.readline()

Veya daha iyi bir yol:

with open('Path/to/file') as f:
    for line in f:
        # do whatever you want to

0

Dosya içeriğini tek bir dize olarak almak yerine, içeriği dosyanın içerdiği tüm satırların bir listesi olarak saklamak kullanışlı olabilir :

with open('Path/to/file', 'r') as content_file:
    content_list = content_file.read().strip().split("\n")

Görüldüğü üzere, tek ihtiyaçları birleştirilmiş yöntemleri eklemek .strip().split("\n")için bu parçacığı ana cevap .

Burada, .strip()tüm dosya dizesinin sonundaki boşluk ve satırsonu karakterlerini kaldırır ve dosya dizesinin .split("\n")tamamını her satırsonu karakterine bölerek gerçek listeyi üretir \ n .

Ayrıca, bu şekilde tüm dosya içeriği, önceki yanıtta belirtildiği gibi dosya satır satır döngü yerine bazı durumlarda istenebilecek bir değişken içinde depolanabilir .

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.