Les objets de type fichier sont des objets en Python qui se comportent comme un vrai fichier, par exemple ont une méthode read () et une méthode write (), mais ont une implémentation différente. C'est et réalisation du concept Duck Typing .
Il est considéré comme une bonne pratique d'autoriser un objet de type fichier partout où un fichier est attendu afin que, par exemple, un objet StringIO ou un objet Socket puisse être utilisé à la place d'un fichier réel. Il est donc mauvais d'effectuer un contrôle comme celui-ci:
if not isinstance(fp, file):
raise something
Quelle est la meilleure façon de vérifier si un objet (par exemple un paramètre d'une méthode) est "semblable à un fichier"?
why
qu'en est-il des opérateurs comme__add__
,__lshift__
ou__or__
dans des classes personnalisées? (objet de fichier et API: docs.python.org/glossary.html#term-file-object )Pour 3.1+, l'un des éléments suivants:
Pour 2.x, "objet semblable à un fichier" est une chose trop vague à vérifier, mais la documentation de la ou des fonctions auxquelles vous avez affaire vous dira avec un peu de chance ce dont elles ont réellement besoin; sinon, lisez le code.
Comme le soulignent d'autres réponses, la première chose à demander est ce que vous recherchez exactement. Habituellement, l'EAFP est suffisant et plus idiomatique.
Le glossaire dit que "objet de type fichier" est un synonyme de "objet fichier", ce qui signifie finalement qu'il s'agit d'une instance de l'une des trois classes de base abstraites définies dans le
io
module , qui sont elles-mêmes toutes des sous-classes deIOBase
. Donc, la façon de vérifier est exactement comme indiqué ci-dessus.(Cependant, la vérification
IOBase
n'est pas très utile. Pouvez-vous imaginer un cas où vous devez distinguer une fonction semblable à un fichierread(size)
d'une fonction à un argument nomméeread
qui n'est pas semblable à un fichier, sans avoir également besoin de faire la distinction entre les fichiers texte et raw Donc, vraiment, vous voulez presque toujours vérifier, par exemple, "est un objet de fichier texte", et non "est un objet de type fichier".)Pour 2.x, alors que le
io
module existe depuis 2.6+, les objets de fichier intégrés ne sont pas des instances deio
classes, aucun des objets de type fichier dans la stdlib non plus, ni la plupart des objets de type fichier tiers que vous sont susceptibles de rencontrer. Il n'y avait pas de définition officielle de ce que signifie «objet semblable à un fichier»; c'est juste "quelque chose comme un objet de fichier intégré ", et différentes fonctions signifient des choses différentes par "comme". Ces fonctions devraient documenter ce qu’elles signifient; s'ils ne le font pas, vous devez regarder le code.Cependant, les significations les plus courantes sont «a
read(size)
», «aread()
» ou «est une itérable de chaînes», mais certaines anciennes bibliothèques peuvent s'attendre à lareadline
place de l'une de celles-ci, certaines bibliothèques aiment lesclose()
fichiers que vous leur donnez, d'autres s'attendent à ce que sifileno
est présente alors d'autres fonctionnalités sont disponibles, etc. Et de même pourwrite(buf)
(bien qu'il y ait beaucoup moins d'options dans cette direction).la source
IOBase
. Par exemple, les appareils pytest vous donnent ce_pytest.capture.EncodedFile
qui n'hérite de rien.Comme d'autres l'ont dit, vous devez généralement éviter de tels contrôles. Une exception est lorsque l'objet peut légitimement être de types différents et que vous souhaitez un comportement différent en fonction du type. La méthode EAFP ne fonctionne pas toujours ici car un objet peut ressembler à plus d'un type de canard!
Par exemple, un initialiseur peut prendre un fichier, une chaîne ou une instance de sa propre classe. Vous pourriez alors avoir du code comme:
L'utilisation d'EAFP ici pourrait causer toutes sortes de problèmes subtils car chaque chemin d'initialisation est partiellement exécuté avant de lancer une exception. Essentiellement, cette construction imite la surcharge de fonctions et n'est donc pas très pythonique, mais elle peut être utile si elle est utilisée avec précaution.
En remarque, vous ne pouvez pas effectuer la vérification des fichiers de la même manière en Python 3. Vous aurez besoin de quelque chose comme à la
isinstance(f, io.IOBase)
place.la source
Le paradigme dominant ici est l'EAFP: plus facile de demander pardon que la permission. Allez-y et utilisez l'interface de fichier, puis gérez l'exception qui en résulte ou laissez-les se propager à l'appelant.
la source
x
n'est pas semblable à un fichier, alorsx.read()
lèvera sa propre exception. Pourquoi écrire une instruction if supplémentaire? Utilisez simplement l'objet. Cela fonctionnera ou se cassera.Il est souvent utile de déclencher une erreur en vérifiant une condition, alors que cette erreur ne serait normalement déclenchée que beaucoup plus tard. Cela est particulièrement vrai pour la frontière entre le code «user-land» et «api».
Vous ne placeriez pas un détecteur de métal dans un poste de police sur la porte de sortie, vous le placeriez à l'entrée! Si le fait de ne pas vérifier une condition signifie qu'une erreur pourrait se produire qui aurait pu être interceptée 100 lignes plus tôt, ou dans une super-classe au lieu d'être levée dans la sous-classe, alors je dis qu'il n'y a rien de mal à vérifier.
La vérification des types appropriés est également judicieuse lorsque vous acceptez plusieurs types. Il est préférable de lever une exception qui dit "J'ai besoin d'une sous-classe de basestring, OR file" plutôt que de simplement lever une exception car une variable n'a pas de méthode 'seek' ...
Cela ne veut pas dire que vous devenez fou et que vous faites cela partout, pour la plupart, je suis d'accord avec le concept d'exceptions se levant d'elles-mêmes, mais si vous pouvez rendre votre API radicalement claire, ou éviter l'exécution de code inutile car une condition simple n'a pas été remplie faites-le!
la source
Vous pouvez essayer d'appeler la méthode puis attraper l'exception:
Si vous ne voulez qu'une méthode de lecture et une méthode d'écriture, vous pouvez le faire:
Si j'étais vous, j'irais avec la méthode try / except.
la source
try
est toujours le premier choix. Leshasattr
chèques sont uniquement - pour une raison vraiment obscure - que vous ne pouvez pas simplement utilisertry
.fp.read(0)
au lieu defp.read()
afin d'éviter de mettre tout le code dans letry
bloc si vous souhaitez traiter les données par lafp
suite.fp.read()
qu'avec de gros fichiers augmentera immédiatement l'utilisation de la mémoire.Flask
j'ai fait cela et j'ai réalisé que l'FileStorage
objet sous-jacent avait besoin de la réinitialisation du pointeur après avoir été lu.Dans la plupart des cas, la meilleure façon de gérer cela est de ne pas le faire. Si une méthode prend un objet de type fichier et qu'il s'avère que l'objet qu'elle a passé ne l'est pas, l'exception qui est déclenchée lorsque la méthode essaie d'utiliser l'objet n'est pas moins informative que toute exception que vous auriez pu déclencher explicitement.
Il y a au moins un cas où vous voudrez peut-être faire ce genre de vérification, cependant, et c'est lorsque l'objet n'est pas immédiatement utilisé par ce à quoi vous l'avez passé, par exemple s'il est défini dans le constructeur d'une classe. Dans ce cas, je pense que le principe de l'EAFP est supplanté par le principe de «l'échec rapide». Je vérifierais l'objet pour m'assurer qu'il implémentait les méthodes dont ma classe a besoin (et qu'elles sont des méthodes), par exemple:
la source
getattr(file, 'read')
au lieu de justefile.read
? Cela fait exactement la même chose.file
instance réelle . (Les méthodes des instances des types intégrés / C-extension sont de typebuiltin_function_or_method
, tandis que celles des classes à l'ancienne le sontinstancemethod
). Le fait qu'il s'agisse d'une classe à l'ancienne, et qu'elle utilise==
sur les types au lieu deininstance
ouissubclass
, sont d'autres problèmes, mais si l'idée de base ne fonctionne pas, cela n'a guère d'importance.J'ai fini par tomber sur ta question alors que j'écrivais un
open
fonction semblable à celle qui pouvait accepter un nom de fichier, un descripteur de fichier ou semblable à un fichier pré-ouvert.Plutôt que de tester une
read
méthode, comme le suggèrent les autres réponses, j'ai fini par vérifier si l'objet peut être ouvert. Si c'est possible, c'est une chaîne ou un descripteur, et j'ai en main un objet de type fichier valide à partir du résultat. Siopen
lève aTypeError
, alors l'objet est déjà un fichier.la source