Dateiähnliche Objekte sind Objekte in Python, die sich wie eine echte Datei verhalten, z. B. eine read () - und eine write-Methode (), aber eine andere Implementierung haben. Es ist und Umsetzung des Duck Typing- Konzepts.
Es wird als bewährte Methode angesehen , ein dateiähnliches Objekt überall dort zuzulassen, wo eine Datei erwartet wird, sodass beispielsweise ein StringIO- oder ein Socket-Objekt anstelle einer realen Datei verwendet werden kann. Es ist also schlecht, eine Prüfung wie folgt durchzuführen:
if not isinstance(fp, file):
raise something
Wie kann am besten überprüft werden, ob ein Objekt (z. B. ein Parameter einer Methode) "dateiähnlich" ist?
why
was Operatoren wie__add__
,__lshift__
oder__or__
in benutzerdefinierten Klassen? ( Dateiobjekt und API: docs.python.org/glossary.html#term-file-object )Für 3.1+ eine der folgenden Möglichkeiten:
Für 2.x ist "dateiähnliches Objekt" zu vage, um es zu überprüfen, aber die Dokumentation für alle Funktionen, mit denen Sie sich befassen, wird Ihnen hoffentlich sagen, was sie tatsächlich benötigen. Wenn nicht, lesen Sie den Code.
Wie andere Antworten zeigen, müssen Sie zunächst fragen, worauf Sie genau achten. Normalerweise ist EAFP ausreichend und idiomatischer.
Das Glossar sagt „file-ähnliches Objekt“ ist ein Synonym für „Dateiobjekt“, was letztlich bedeutet , dass es eine Instanz von einem der drei ist abstrakte Basisklassen in definiert das
io
Modul , die sich alle Subklassen von sindIOBase
. Die Art der Überprüfung ist also genau wie oben gezeigt.(Die Überprüfung
IOBase
ist jedoch nicht sehr nützlich. Können Sie sich einen Fall vorstellen, in dem Sie eine tatsächliche dateiähnlicheread(size)
Funktion von einer Funktion mit einem Argument unterscheiden müssenread
, die nicht dateiähnlich ist, ohne auch zwischen Textdateien und RAW unterscheiden zu müssen? Binärdateien? Sie möchten also eigentlich fast immer überprüfen, z. B. "Ist ein Textdateiobjekt", nicht "Ist ein dateiähnliches Objekt".)Während das
io
Modul für 2.x seit 2.6+ existiert, sind integrierte Dateiobjekte keine Instanzen vonio
Klassen, keines der dateiähnlichen Objekte in der stdlib und auch nicht die meisten dateiähnlichen Objekte von Drittanbietern sind wahrscheinlich zu begegnen. Es gab keine offizielle Definition dessen, was "dateiähnliches Objekt" bedeutet; es ist nur „so etwas wie ein eingebautes Dateiobjekt “, und verschiedene Funktionen bedeuten verschiedene Dinge durch „wie“. Solche Funktionen sollten dokumentieren, was sie bedeuten; Wenn dies nicht der Fall ist, müssen Sie sich den Code ansehen.Die gebräuchlichsten Bedeutungen sind jedoch "hat
read(size)
", "hatread()
" oder "ist eine Iteration von Zeichenfolgen", aber einige alte Bibliotheken erwarten möglicherweisereadline
anstelle einer dieser, einige Bibliotheken mögenclose()
Dateien, die Sie ihnen geben, andere erwarten dies, wennfileno
vorhanden ist, dann sind andere Funktionen verfügbar usw. Und ähnlich fürwrite(buf)
(obwohl es in dieser Richtung viel weniger Optionen gibt).quelle
IOBase
. Zum Beispiel geben Ihnen Pytest-Scheinwerfer,_pytest.capture.EncodedFile
die von nichts erben.Wie andere gesagt haben, sollten Sie solche Überprüfungen generell vermeiden. Eine Ausnahme ist, wenn das Objekt zu Recht unterschiedliche Typen hat und Sie je nach Typ ein unterschiedliches Verhalten wünschen. Die EAFP-Methode funktioniert hier nicht immer, da ein Objekt wie mehr als eine Entenart aussehen kann!
Ein Initialisierer könnte beispielsweise eine Datei, einen String oder eine Instanz seiner eigenen Klasse verwenden. Sie könnten dann Code haben wie:
Die Verwendung von EAFP kann hier alle möglichen subtilen Probleme verursachen, da jeder Initialisierungspfad teilweise ausgeführt wird, bevor eine Ausnahme ausgelöst wird. Im Wesentlichen ahmt diese Konstruktion die Überlastung der Funktion nach und ist daher nicht sehr pythonisch, kann jedoch bei vorsichtiger Verwendung nützlich sein.
Nebenbei bemerkt, Sie können die Dateiprüfung in Python 3 nicht auf die gleiche Weise durchführen
isinstance(f, io.IOBase)
. Stattdessen benötigen Sie so etwas wie .quelle
Das vorherrschende Paradigma ist hier EAFP: leichter um Vergebung als um Erlaubnis zu bitten. Verwenden Sie die Dateischnittstelle, behandeln Sie dann die resultierende Ausnahme oder lassen Sie sie an den Aufrufer weitergeben.
quelle
x
es nicht dateiähnlich ist,x.read()
wird eine eigene Ausnahme ausgelöst. Warum eine zusätzliche if-Anweisung schreiben? Verwenden Sie einfach das Objekt. Es wird entweder funktionieren oder brechen.Es ist oft nützlich, einen Fehler durch Überprüfen einer Bedingung auszulösen, wenn dieser Fehler normalerweise erst viel später ausgelöst wird. Dies gilt insbesondere für die Grenze zwischen "User-Land" - und "API" -Code.
Sie würden keinen Metalldetektor auf einer Polizeistation an der Ausgangstür platzieren, Sie würden ihn am Eingang platzieren! Wenn das Nichtprüfen einer Bedingung bedeutet, dass möglicherweise ein Fehler auftritt, der 100 Zeilen früher oder in einer Superklasse abgefangen werden könnte, anstatt in der Unterklasse ausgelöst zu werden, ist die Überprüfung nichts Falsches.
Die Überprüfung auf korrekte Typen ist auch dann sinnvoll, wenn Sie mehr als einen Typ akzeptieren. Es ist besser, eine Ausnahme mit der Meldung "Ich benötige eine Unterklasse von Basisstreifen oder ODER-Datei" auszulösen, als nur eine Ausnahme auszulösen, da einige Variablen keine Suchmethode haben ...
Dies bedeutet nicht, dass Sie verrückt werden und dies überall tun. Zum größten Teil stimme ich dem Konzept zu, dass Ausnahmen sich selbst auslösen. Wenn Sie jedoch Ihre API drastisch klarstellen oder unnötige Codeausführung vermeiden können, weil eine einfache Bedingung nicht erfüllt ist tun Sie dies!
quelle
Sie können versuchen, die Methode aufzurufen und dann die Ausnahme abfangen:
Wenn Sie nur eine Lese- und eine Schreibmethode wünschen, können Sie dies tun:
Wenn ich du wäre, würde ich mit der try / Except-Methode gehen.
quelle
try
ist immer die erste Wahl. Diehasattr
Schecks sind nur - aus einem wirklich unbekannten Grund - nicht einfach zu verwendentry
.fp.read(0)
anstelle vonfp.read()
zu verwenden, um zu vermeiden, dass der gesamte Code in dentry
Block eingefügt wird, wenn Sie die Datenfp
anschließend verarbeiten möchten .fp.read()
bei großen Dateien die Speichernutzung sofort erhöht wird.Flask
ich dies getan und festgestellt, dass das zugrunde liegendeFileStorage
Objekt nach dem Lesen einen Zeiger zurücksetzen muss.In den meisten Fällen ist dies am besten nicht der Fall. Wenn eine Methode ein dateiähnliches Objekt verwendet und sich herausstellt, dass das übergebene Objekt nicht vorhanden ist, ist die Ausnahme, die ausgelöst wird, wenn die Methode versucht, das Objekt zu verwenden, nicht weniger informativ als jede Ausnahme, die Sie möglicherweise explizit ausgelöst haben.
Es gibt jedoch mindestens einen Fall, in dem Sie diese Art der Überprüfung durchführen möchten, und dann wird das Objekt nicht sofort von dem verwendet, an das Sie es übergeben haben, z. B. wenn es im Konstruktor einer Klasse festgelegt wird. In diesem Fall würde ich denken, dass das Prinzip der EAFP durch das Prinzip "schnell scheitern" übertroffen wird. Ich würde das Objekt überprüfen, um sicherzustellen, dass es die Methoden implementiert, die meine Klasse benötigt (und dass es sich um Methoden handelt), z.
quelle
getattr(file, 'read')
statt nurfile.read
? Dies macht genau das Gleiche.file
beispielsweise eine tatsächliche Instanz angegeben wird. (Methoden von Instanzen von eingebauten / C-Erweiterungstypen sind vom Typbuiltin_function_or_method
, während die von Klassen alten Stils sindinstancemethod
). Die Tatsache, dass dies eine Klasse alten Stils ist und==
für Typen anstelle vonininstance
oder verwendet wirdissubclass
, sind weitere Probleme, aber wenn die Grundidee nicht funktioniert, spielt das kaum eine Rolle.Ich bin auf Ihre Frage gestoßen, als ich eine
open
ähnliche Funktion geschrieben habe, die einen Dateinamen, einen Dateideskriptor oder ein vorgeöffnetes dateiähnliches Objekt akzeptieren kann.Anstatt nach einer
read
Methode zu testen , wie die anderen Antworten vermuten lassen, habe ich am Ende geprüft, ob das Objekt geöffnet werden kann. Wenn dies möglich ist, handelt es sich um eine Zeichenfolge oder einen Deskriptor, und ich habe aus dem Ergebnis ein gültiges dateiähnliches Objekt in der Hand. Wenn aopen
ausgelöst wirdTypeError
, ist das Objekt bereits eine Datei.quelle