Odpowiedzi:
Odpowiedź na to pytanie zależy w pewnym stopniu od konkretnej implementacji języka Python.
Aby zrozumieć, o co w tym wszystkim chodzi, zwróć szczególną uwagę na rzeczywisty file
przedmiot. W kodzie ten obiekt jest wymieniony tylko raz, w wyrażeniu, i staje się niedostępny natychmiast po read()
powrocie wywołania.
Oznacza to, że obiekt pliku jest śmieci. Pozostaje tylko pytanie: „Kiedy śmieciarz zbierze obiekt pliku?”.
w CPython, który korzysta z licznika referencyjnego, ten rodzaj śmieci jest natychmiast zauważany, a więc zostanie natychmiast zebrany. Zasadniczo nie dotyczy to innych implementacji języka Python.
Lepszym rozwiązaniem, aby upewnić się, że plik jest zamknięty, jest następujący wzorzec:
with open('Path/to/file', 'r') as content_file:
content = content_file.read()
co zawsze zamyka plik natychmiast po zakończeniu bloku; nawet jeśli wystąpi wyjątek.
Edycja: Aby dodać drobniejszy punkt:
Poza tym file.__exit__()
, które jest „automatycznie” wywoływane w with
ustawieniach menedżera kontekstu, jedynym innym sposobem, który file.close()
jest wywoływany automatycznie (to znaczy inaczej niż jawne wywoływanie go osobiście) jest poprzez file.__del__()
. To prowadzi nas do pytania, kiedy __del__()
zostanie wywołany?
Prawidłowo napisany program nie może zakładać, że finalizatory będą działać w dowolnym momencie przed zakończeniem programu.
- https://devblogs.microsoft.com/oldnewthing/20100809-00/?p=13203
W szczególności:
Obiekty nigdy nie są jawnie niszczone; jednak gdy staną się nieosiągalne, mogą zostać zebrane w śmieci. Implementacja może odroczyć odrzucanie elementów bezużytecznych lub całkowicie je pominąć - kwestią jakości implementacji jest sposób, w jaki jest ono stosowane, o ile nie są gromadzone obiekty, które są nadal dostępne.
[...]
CPython obecnie używa schematu zliczania referencji z (opcjonalnym) opóźnionym wykrywaniem cyklicznie powiązanych śmieci, które zbierają większość obiektów, gdy tylko stają się one nieosiągalne, ale nie ma gwarancji, że zbierają śmieci zawierające cykliczne odwołania.
- https://docs.python.org/3.5/reference/datamodel.html#objects-values-and-types
(Moje podkreślenie)
ale jak sugeruje, inne implementacje mogą mieć inne zachowanie. Na przykład PyPy ma 6 różnych implementacji odśmiecania !
__exit__()
w takich przypadkach brzmi jak wada projektowa.
try
/ finally
jest niespokojny i bardzo często bezużyteczny dla programów czyszczących, które with
rozwiązują. Różnica między „jawnym zamykaniem” a „zarządzaniem za pomocą with
” polega na tym, że program obsługi wyjścia jest wywoływany, nawet jeśli zostanie zgłoszony wyjątek. Można umieścić close()
w finally
klauzuli, ale nie różni się zbytnio od używania with
zamiast, trochę Messiera (3 dodatkowe linie zamiast 1), a trochę trudniej dostać tylko w prawo.
with foo() as f: [...]
jest w zasadzie taka sama jak f = foo()
, f.__enter__()
[...] oraz f.__exit__()
z wyjątkami obsługiwane tak, że __exit__
zawsze jest wywoływana. Plik zawsze się zamyka.
Możesz użyć pathlib .
W przypadku języka Python 3.5 i nowszych:
from pathlib import Path
contents = Path(file_path).read_text()
W przypadku starszych wersji Pythona użyj pathlib2 :
$ pip install pathlib2
Następnie:
from pathlib2 import Path
contents = Path(file_path).read_text()
To jest faktyczna read_text
implementacja :
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()
Cóż, jeśli musisz czytać plik linia po linii, aby pracować z każdą linią, możesz użyć
with open('Path/to/file', 'r') as f:
s = f.readline()
while s:
# do whatever you want to
s = f.readline()
Lub jeszcze lepszy sposób:
with open('Path/to/file') as f:
for line in f:
# do whatever you want to
Zamiast pobierać zawartość pliku jako pojedynczy ciąg, przydatne może być przechowywanie zawartości jako listy wszystkich wierszy pliku :
with open('Path/to/file', 'r') as content_file:
content_list = content_file.read().strip().split("\n")
Jak widać, należy dodać połączone metody .strip().split("\n")
do głównej odpowiedzi w tym wątku .
Tutaj .strip()
po prostu usuwa znaki białych znaków i znaków nowej linii na końcach całego ciągu pliku i .split("\n")
tworzy rzeczywistą listę poprzez podział całego łańcucha pliku przy każdym znaku nowego wiersza \ n .
Ponadto w ten sposób cała zawartość pliku może być przechowywana w zmiennej, co może być pożądane w niektórych przypadkach, zamiast zapętlania pliku po linii, jak wskazano w poprzedniej odpowiedzi .