Jeśli czytasz cały plik, content = open('Path/to/file', 'r').read()
czy uchwyt pliku pozostaje otwarty, dopóki skrypt nie zostanie zamknięty? Czy istnieje bardziej zwięzła metoda odczytu całego pliku?
Jeśli czytasz cały plik, content = open('Path/to/file', 'r').read()
czy uchwyt pliku pozostaje otwarty, dopóki skrypt nie zostanie zamknięty? Czy istnieje bardziej zwięzła metoda odczytu całego pliku?
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órewith
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()
wfinally
klauzuli, ale nie różni się zbytnio od używaniawith
zamiast, trochę Messiera (3 dodatkowe linie zamiast 1), a trochę trudniej dostać tylko w prawo.with foo() as f: [...]
jest w zasadzie taka sama jakf = foo()
,f.__enter__()
[...] orazf.__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:
W przypadku starszych wersji Pythona użyj pathlib2 :
Następnie:
To jest faktyczna
read_text
implementacja :źródło
Cóż, jeśli musisz czytać plik linia po linii, aby pracować z każdą linią, możesz użyć
Lub jeszcze lepszy sposób:
źródło
Zamiast pobierać zawartość pliku jako pojedynczy ciąg, przydatne może być przechowywanie zawartości jako listy wszystkich wierszy pliku :
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 .
źródło