2009-09-16 13 views
26

Załóżmy, że chcemy zaimplementować odpowiednik PHP file_get_content.jak zdobyć zawartość małego pliku ASCII w Pythonie?

Jaka jest najlepsza praktyka? (elegancki i niezawodny)

Oto kilka propozycji, czy są one prawidłowe?

użyciu with oświadczenie:

def file_get_contents(filename): 
    with file(filename) as f: 
     s = f.read() 
    return s 

obsługuje standard open() bezpieczne?

def file_get_contents(filename): 
    return open(filename).read() 

Co dzieje się z deskryptorem pliku w obu rozwiązaniach?

Odpowiedz

39

W obecnej realizacji CPython, jak będzie na ogół natychmiast zamknij plik. Jednak język Python nie daje takiej gwarancji dla drugiego - plik zostanie ostatecznie zamknięty, ale finalizator może nie zostać wywołany do następnego cyklu GC. Implementacje takie jak Jython i IronPython będą działać w ten sposób, więc dobrą praktyką jest wyraźne zamykanie plików.

Powiedziałbym, że używanie pierwszego rozwiązania jest najlepszą praktyką, chociaż zazwyczaj preferowane jest open z file. Należy pamiętać, że można ją skrócić trochę chociaż jeśli wolisz zwięzłość drugim przykładzie:

def file_get_contents(filename): 
    with open(filename) as f: 
     return f.read() 

__exit__ częścią kierownika kontekstowego będzie wykonywał po opuszczeniu ciała do żadnego powodu, w tym wyjątków i powrocie z funkcji - nie ma potrzeby stosowania zmiennej pośredniej.

+1

od PEP 343: http://www.python.org/dev/peps/pep-0343 Należy pamiętać, że nie jesteśmy gwarantując, że w końcu klauzula jest wykonywany natychmiast po obiekcie generatora staje nieużywany, choć jest to jak to będzie działać w CPython. Jest to podobne do automatycznego zamykania plików: podczas gdy implementacja liczenia odwołań, jak CPython, powoduje zwolnienie obiektu, gdy zniknie ostatnie odwołanie do niego, implementacje używające innych algorytmów GC nie dają tej samej gwarancji. Odnosi się to do Jython, IronPython i prawdopodobnie do Pythona działającego na Parrot. – kriss

+0

@kriss: Zauważ, że nie jest to sprzeczne oświadczenia o prowadzeniu '__exit__' gdy opuszcza ciało - to tylko szczegóły tego, co się dzieje, jeśli ** nie ** wyjście ciało poprzez generator zawieszony w menedżerze kontekstowego i jak Python zmusi go do odejścia przez podniesienie wyjątku. – Brian

2

with spowoduje, że plik zostanie zamknięty, gdy blok zostanie pozostawiony.

W twoim drugim przykładzie uchwyt pliku może pozostać otwarty (Python nie daje gwarancji, że jest zamknięty lub gdy nie robisz tego wyraźnie).

+4

niezupełnie. W CPython plik jest zamykany, gdy tylko deskryptor pliku wykracza poza zakres - na pewno do czasu powrotu funkcji. (Sprawdziłem źródło Pythona, ponieważ ostatnio pojawił się on w innym miejscu.) W IronPython i Jython plik zostanie zamknięty, gdy obiekt pliku zostanie zbufowany, ale nie ma gwarancji, kiedy to nastąpi. –

+0

Jeśli nie używasz opcji 'with', plik jest zamykany nawet w przypadku wyjątku? –

+1

@Hank Gay: jeśli nie "z" nie ma gwarancji - deskryptor pliku OS może pozostać otwarty. –

1
import os 

def file_get_contents(filename): 
    if os.path.exists(filename): 
    fp = open(filename, "r") 
    content = fp.read() 
    fp.close() 
    return content 

Przypadek ten zwróci None, jeśli plik nie istnieje, a deskryptor pliku zostanie zamknięty przed zakończeniem funkcji.

+4

Tęsknota za używaniem 'z' - ten kod ma tę samą słabość co jawne' nowy/delete' w kodzie C++ - w przypadku jakiegokolwiek wyjątku interweniującego przed kodem oczyszczania, oczyszczanie po prostu się nie dzieje. We wcześniejszych wersjach Pythona, można zawrzeć ten przykład w 'try/catch/finally', ale fajne dzieci używają' with'. – PaulMcG

+0

To pomija kwestię pytania o niezawodność. Dodaje niepotrzebne funkcje (sprawdzanie istnienia pliku) i nie jest szczególnie elegancki (importowanie os i długości kodu). – vaab

3

Używanie instrukcji with jest tak naprawdę najmilszym sposobem, aby być pewnym, że plik jest naprawdę zamknięty.

zależności od zachowania śmieciarza za zadanie to może działać, ale w tym przypadku nie jest to dobry sposób, aby mieć pewność, we wszystkich przypadkach, więc ...

-1

Można również użyć funkcji Pythona v3:

>>> ''.join(open('htdocs/config.php', 'r').readlines()) 
"This is the first line of the file.\nSecond line of the file" 

Czytaj więcej http://docs.python.org/py3k/tutorial/inputoutput.html

+1

Bądź ostrożny przy pisaniu kopiowanie i wklejanie szablonowe/dosłownych odpowiedzi na wiele pytań, te wydają się być oznaczony jako „spam” przez społeczność. Jeśli to robisz, oznacza to zazwyczaj, że pytania są duplikowane, więc oznacz je jako takie. http://stackoverflow.com/questions/1433577 – Kev

Powiązane problemy