Angenommen, ich habe eine Funktion, die Dinge mit einer Textdatei ausführt - zum Beispiel liest sie aus und entfernt das Wort 'a'. Ich könnte ihm entweder einen Dateinamen übergeben und das Öffnen / Schließen in der Funktion handhaben, oder ich könnte ihm die geöffnete Datei übergeben und erwarten, dass jeder, der sie aufruft, damit umgehen würde, sie zu schließen.
Der erste Weg scheint ein besserer Weg zu sein, um sicherzustellen, dass keine Dateien offen bleiben, hindert mich jedoch daran, Dinge wie StringIO-Objekte zu verwenden
Der zweite Weg könnte ein wenig gefährlich sein - keine Möglichkeit zu wissen, ob die Datei geschlossen wird oder nicht, aber ich könnte dateiähnliche Objekte verwenden
def ver_1(filename):
with open(filename, 'r') as f:
return do_stuff(f)
def ver_2(open_file):
return do_stuff(open_file)
print ver_1('my_file.txt')
with open('my_file.txt', 'r') as f:
print ver_2(f)
Ist eine davon generell bevorzugt? Wird allgemein erwartet, dass sich eine Funktion auf eine dieser beiden Arten verhält? Oder sollte es nur so gut dokumentiert sein, dass der Programmierer die Funktion entsprechend nutzen kann?
quelle
your_function
In diesem Zusammenhang kann ein optionales Argument "stream_name" verwendet werden.Die eigentliche Frage ist die Vollständigkeit. Handelt es sich bei Ihrer Dateiverarbeitungsfunktion um die vollständige Verarbeitung der Datei, oder handelt es sich nur um ein Teil einer Reihe von Verarbeitungsschritten? Wenn es vollständig ist, können Sie den gesamten Dateizugriff in einer Funktion einschließen.
Dies hat die sehr schöne Eigenschaft, die Ressource am Ende der
with
Anweisung zu finalisieren (die Datei zu schließen) .Wenn es jedoch möglicherweise erforderlich ist, eine bereits geöffnete Datei zu verarbeiten, ist die Unterscheidung von
ver_1
undver_2
sinnvoller. Zum Beispiel:Diese Art der expliziten Typprüfung wird häufig verpönt , insbesondere in Sprachen wie Java, Julia und Go, in denen typ- oder schnittstellenbasiertes Dispatching direkt unterstützt wird. In Python gibt es jedoch keine Sprachunterstützung für typbasiertes Dispatching. Es kann gelegentlich vorkommen, dass Sie in Python Kritik an direkten Typprüfungen üben, in der Praxis ist dies jedoch äußerst verbreitet und recht effektiv. Es ermöglicht einer Funktion ein hohes Maß an Allgemeingültigkeit, wobei alle Datentypen behandelt werden, die wahrscheinlich ihren Weg finden, auch bekannt als "Duck Typing". Beachten Sie den führenden Unterstrich an
_ver_file
; Dies ist eine herkömmliche Art, eine "private" Funktion (oder Methode) zu bezeichnen. Sie kann zwar technisch direkt aufgerufen werden, weist jedoch darauf hin, dass die Funktion nicht für den direkten externen Verbrauch vorgesehen ist.Update 2019: Angesichts der jüngsten Aktualisierungen in Python 3, zum Beispiel, dass Pfade jetzt möglicherweise
pathlib.Path
nicht nur als Objektestr
oderbytes
(3.4+) gespeichert werden und dieser Hinweis vom Esoterischen zum Mainstream übergegangen ist (ca. 3.6+, obwohl er sich immer noch aktiv weiterentwickelt), hier aktualisierter Code, der diese Fortschritte berücksichtigt:quelle
read
etwas aufzurufen , das einer Datei ähnelt , oder wenn Sieopen(fileobj, 'r')
dasTypeError
if aufrufen und abfangen, dasfileobj
keine Zeichenfolge ist.ver
Operation unabhängig vom Typ. Es könnte auch möglich seinver
, wie Sie sagen, durch Duck Typing zu implementieren . Das Erzeugen von Ausnahmen ist jedoch langsamer als das einfache Prüfen von Typen, und IMO bietet keinen besonderen Vorteil (Klarheit, Allgemeingültigkeit usw.). Meiner Erfahrung nach ist das Tippen von Enten "im Großen" großartig, aber im Kleinen neutral bis kontraproduktiv . "hasattr(fileobj, 'read')
Test wäre Entenschreiben; Einisinstance(fileobj, str)
Test ist das nicht. Hier ist ein Beispiel für den Unterschied: Derisinstance
Test schlägt mit Unicode-Dateinamen fehl, da diesu'adsf.txt'
nicht der Fall iststr
. Sie haben auf einen zu spezifischen Typ getestet. Ein Enten-Typisierungstest, ob basierend auf Aufrufenopen
oder einer hypothetischendoes_this_object_represent_a_filename
Funktion, hätte dieses Problem nicht.is_instance(x, str)
sondern eher so etwas wieis_instance(x, string_types)
,string_types
wenn er für den ordnungsgemäßen Betrieb zwischen PY2 und PY3 richtig eingestellt wäre. Wenn etwas gegeben wird, das wie eine Schnur quakt,ver
würde es richtig reagieren. etwas gegeben, das wie eine Datei quakt, das gleiche. Für einen Benutzer vonver
würde es keinen Unterschied geben - außer dass die Implementierung der Typprüfung schneller laufen würde. Entenpuristen: Zögern Sie nicht.Wenn Sie den Dateinamen anstelle des Datei-Handles weitergeben, kann nicht garantiert werden, dass die zweite Datei dieselbe Datei ist wie die erste, wenn sie geöffnet wird. Dies kann zu Korrektheitsproblemen und Sicherheitslücken führen.
quelle
Hier geht es um das Eigentum und die Verantwortung, die Datei zu schließen. Sie können auf einem Stream oder Datei - Handle übergeben oder was auch immer Dingen , das geschlossen werden soll / an einem gewissen Punkt zu einem anderen Verfahren angeordnet ist , solange Sie sicherstellen , dass es klar ist , wer es besitzt und sicher , es wird vom Eigentümer geschlossen werden , wenn Sie fertig sind , . Dies beinhaltet typischerweise ein Endversuchskonstrukt oder das Wegwerfmuster.
quelle
Wenn Sie geöffnete Dateien übergeben möchten, können Sie etwas wie das folgende tun, ABER Sie haben keinen Zugriff auf den Dateinamen in der Funktion, die in die Datei schreibt.
Ich würde dies tun, wenn ich eine Klasse haben möchte, die zu 100% für Datei- / Stream-Vorgänge verantwortlich ist, und andere Klassen oder Funktionen, die naiv wären und die Dateien / Streams nicht öffnen oder schließen sollen.
Denken Sie daran, dass Kontextmanager wie eine finally-Klausel funktionieren. Wenn also eine Ausnahme in der Writer-Funktion ausgelöst wird, wird die Datei geschlossen, egal was passiert.
quelle
with open
? Wie wird die Frage der Verwendung von Dateinamen im Vergleich zu dateiähnlichen Objekten beantwortet?with open
, oder? Und was Sie effektiv befürworten, ist eine Funktion, die nur dateiähnliche Objekte verwendet und sich nicht darum kümmert, woher sie stammt?