Quelle est la meilleure façon de vérifier si un objet donné est d'un type donné? Que diriez-vous de vérifier si l'objet hérite d'un type donné?
Disons que j'ai un objet o
. Comment puis-je vérifier s'il s'agit d'un str
?
Quelle est la meilleure façon de vérifier si un objet donné est d'un type donné? Que diriez-vous de vérifier si l'objet hérite d'un type donné?
Disons que j'ai un objet o
. Comment puis-je vérifier s'il s'agit d'un str
?
Réponses:
Pour vérifier s'il o
s'agit d'une instance str
ou d'une sous-classe de str
, utilisez isinstance (ce serait la méthode "canonique"):
if isinstance(o, str):
Pour vérifier si le type de o
est exactement str
(exclure les sous-classes):
if type(o) is str:
Les éléments suivants fonctionnent également et peuvent être utiles dans certains cas:
if issubclass(type(o), str):
Voir Fonctions intégrées dans la référence de la bibliothèque Python pour des informations pertinentes.
Une dernière remarque: dans ce cas, si vous utilisez Python 2, vous voudrez peut-être utiliser:
if isinstance(o, basestring):
car cela interceptera également les chaînes Unicode ( unicode
n'est pas une sous-classe de str
; les deux str
et unicode
sont des sous-classes de basestring
). Notez qu'il basestring
n'existe plus en Python 3, où il y a une séparation stricte des chaînes ( str
) et des données binaires ( bytes
).
Alternativement, isinstance
accepte un tuple de classes. Cela retournera True
si o
est une instance d'une sous-classe de l'un des (str, unicode)
:
if isinstance(o, (str, unicode)):
type(a) is Object
alors n'est-ce pas également vrai isinstance(a, Object)
. Cependant, si type(a) is SubClassOfObject
, alors type(a) is Object == False
, mais isinstance(a, Object) == True
. Droite?
a is b
signifie que a et b sont exactement la même chose, c'est-à-dire des références à la même entité en mémoire. Donc, a
et b
devrait être exactement la même classe, pas des sous-classes, comme avec isinstance()
. Voir par exemple stackoverflow.com/a/133024/1072212
La façon la plus pythonique de vérifier le type d'un objet est ... de ne pas le vérifier.
Étant donné que Python encourage Duck Typing , vous devez simplement try...except
utiliser les méthodes de l'objet comme vous le souhaitez. Donc, si votre fonction recherche un objet fichier inscriptible, ne vérifiez pas qu'il s'agit d'une sous-classe de file
, essayez simplement d'utiliser sa .write()
méthode!
Bien sûr, parfois ces belles abstractions se décomposent et isinstance(obj, cls)
c'est ce dont vous avez besoin. Mais utilisez avec parcimonie.
if hasattr(ob, "write") and callable(ob.write):
Ou enregistrer un accès dict ...func = getattr(ob, "write", None)
if callable(func): ...
hasattr
ne supprime qu'une AttributeError - Voir: docs.python.org/3.4/library/functions.html#hasattr
isinstance(o, str)
retournera True
si o
est un str
ou est d'un type qui hérite de str
.
type(o) is str
retournera True
si et seulement si o
est une chaîne. Il retournera False
si o
est d'un type qui hérite de str
.
isinstance
et type(var) == type('')
n'est pas claire.
Après que la question a été posée et répondue, des indices de type ont été ajoutés à Python . Les indices de type en Python permettent de vérifier les types mais d'une manière très différente des langages typés statiquement. Les indices de type en Python associent les types d'arguments attendus aux fonctions en tant que données accessibles à l'exécution associées aux fonctions, ce qui permet de vérifier les types. Exemple de syntaxe d'indication de type:
def foo(i: int):
return i
foo(5)
foo('oops')
Dans ce cas, nous voulons qu'une erreur soit déclenchée foo('oops')
car le type annoté de l'argument est int
. L'indicateur de type ajouté ne provoque pas d'erreur lors de l'exécution normale du script. Cependant, il ajoute des attributs à la fonction décrivant les types attendus que d'autres programmes peuvent interroger et utiliser pour vérifier les erreurs de type.
L'un de ces autres programmes qui peuvent être utilisés pour rechercher l'erreur de type est mypy
:
mypy script.py
script.py:12: error: Argument 1 to "foo" has incompatible type "str"; expected "int"
(Vous devrez peut-être installer à mypy
partir de votre gestionnaire de paquets. Je ne pense pas qu'il soit livré avec CPython mais semble avoir un certain niveau d '"officialité".)
La vérification de type de cette manière est différente de la vérification de type dans les langages compilés de type statique. Étant donné que les types sont dynamiques en Python, la vérification de type doit être effectuée au moment de l'exécution, ce qui impose un coût - même sur les programmes corrects - si nous insistons pour que cela se produise à chaque chance. Les vérifications de type explicites peuvent également être plus restrictives que nécessaire et provoquer des erreurs inutiles (par exemple, l'argument doit-il vraiment être exactement de list
type ou quelque chose d'itérable est-il suffisant?).
L'avantage de la vérification de type explicite est qu'il peut détecter les erreurs plus tôt et donner des messages d'erreur plus clairs que la frappe de canard. Les exigences exactes d'un type de canard ne peuvent être exprimées qu'avec une documentation externe (espérons-le, elle est complète et précise) et des erreurs de types incompatibles peuvent se produire loin de leur origine.
Les conseils de type de Python sont censés offrir un compromis où les types peuvent être spécifiés et vérifiés mais il n'y a aucun coût supplémentaire lors de l'exécution de code habituelle.
Le typing
package propose des variables de type qui peuvent être utilisées dans des conseils de type pour exprimer les comportements nécessaires sans nécessiter de types particuliers. Par exemple, il inclut des variables telles que Iterable
et Callable
pour des conseils pour spécifier la nécessité de tout type avec ces comportements.
Bien que les indices de type soient la façon la plus Pythonique de vérifier les types, il est souvent encore plus Pythonic de ne pas vérifier les types du tout et de s'appuyer sur la frappe de canard. Les indices de type sont relativement nouveaux et le jury n'est toujours pas sur le moment où ils sont la solution la plus Pythonic. Une comparaison relativement peu controversée mais très générale: les astuces de type fournissent une forme de documentation qui peut être appliquée, permettre au code de générer des erreurs plus tôt et plus faciles à comprendre, peut détecter des erreurs que la frappe de canard ne peut pas, et peut être vérifiée statiquement (dans un cas inhabituel sens mais il est toujours en dehors de l'exécution). D'un autre côté, le typage canard est la méthode Pythonique depuis longtemps, n'impose pas le surcoût cognitif du typage statique, est moins verbeux et accepte tous les types viables, puis certains.
mypy
est un module Python qui utilise importlib
pour accéder à ces données. Que ce soit une "vérification de type statique" est une question philosophique mais elle est différente de ce que la plupart des gens pourraient attendre puisque l'interpréteur de langage normal et le mécanisme d'importation sont impliqués.
Voici un exemple pour lequel la frappe de canard est mauvaise sans savoir quand elle est dangereuse. Par exemple: Voici le code Python (en omettant éventuellement une indentation appropriée), notez que cette situation est évitable en prenant soin des fonctions isinstance et issubclassof pour vous assurer que lorsque vous avez vraiment besoin d'un canard, vous n'obtenez pas de bombe.
class Bomb:
def __init__(self):
""
def talk(self):
self.explode()
def explode(self):
print "BOOM!, The bomb explodes."
class Duck:
def __init__(self):
""
def talk(self):
print "I am a duck, I will not blow up if you ask me to talk."
class Kid:
kids_duck = None
def __init__(self):
print "Kid comes around a corner and asks you for money so he could buy a duck."
def takeDuck(self, duck):
self.kids_duck = duck
print "The kid accepts the duck, and happily skips along"
def doYourThing(self):
print "The kid tries to get the duck to talk"
self.kids_duck.talk()
myKid = Kid()
myBomb = Bomb()
myKid.takeDuck(myBomb)
myKid.doYourThing()
class EvilDuck(Duck)
conversation et la remplacer (). Ou plus probablement, class ChineseCancerDuck(Duck)
avec un effet secondaire désagréable qui n'apparaît que des années plus tard. Vous feriez mieux de superviser votre enfant (et de tester ses jouets à fond :)
__file__
attribut (couramment utilisé pour identifier les objets de type fichier) pour signifier autre chose.
isinstance(o, str)
Je pense que la bonne chose à propos de l'utilisation d'un langage dynamique comme Python est que vous ne devriez vraiment pas avoir à vérifier quelque chose comme ça.
Je voudrais simplement appeler les méthodes requises sur votre objet et attraper un AttributeError
. Plus tard, cela vous permettra d'appeler vos méthodes avec d'autres objets (apparemment sans rapport) pour accomplir différentes tâches, telles que se moquer d'un objet à tester.
J'ai beaucoup utilisé cela pour obtenir des données du Web avec urllib2.urlopen()
lesquelles renvoie un fichier comme un objet. Cela peut à son tour être transmis à presque n'importe quelle méthode qui lit à partir d'un fichier, car il implémente la même read()
méthode qu'un fichier réel.
Mais je suis sûr qu'il y a un temps et un lieu d'utilisation isinstance()
, sinon il ne serait probablement pas là :)
Pour les validations de types plus complexes, j'aime l'approche de typeguard de la validation basée sur les annotations d' indices de type python:
from typeguard import check_type
from typing import List
try:
check_type('mylist', [1, 2], List[int])
except TypeError as e:
print(e)
Vous pouvez effectuer des validations très complexes de manière très propre et lisible.
check_type('foo', [1, 3.14], List[Union[int, float]])
# vs
isinstance(foo, list) and all(isinstance(a, (int, float)) for a in foo)
Vous pouvez vérifier le type d'une variable en utilisant __name__ d'un type.
Ex:
>>> a = [1,2,3,4]
>>> b = 1
>>> type(a).__name__
'list'
>>> type(a).__name__ == 'list'
True
>>> type(b).__name__ == 'list'
False
>>> type(b).__name__
'int'
À Hugo:
Vous voulez probablement dire list
plutôt que array
, mais cela pointe tout le problème de la vérification de type - vous ne voulez pas savoir si l'objet en question est une liste, vous voulez savoir s'il s'agit d'une sorte de séquence ou s'il s'agit d'un seul objet. Essayez donc de l'utiliser comme une séquence.
Supposons que vous souhaitiez ajouter l'objet à une séquence existante, ou s'il s'agit d'une séquence d'objets, ajoutez-les tous
try:
my_sequence.extend(o)
except TypeError:
my_sequence.append(o)
Une astuce avec cela est si vous travaillez avec des chaînes et / ou des séquences de chaînes - c'est délicat, car une chaîne est souvent considérée comme un seul objet, mais c'est aussi une séquence de caractères. Pire que cela, car c'est vraiment une séquence de cordes de longueur unique.
Je choisis généralement de concevoir mon API de sorte qu'elle n'accepte qu'une seule valeur ou une séquence - cela facilite les choses. Il n'est pas difficile de mettre un [ ]
autour de votre valeur unique lorsque vous la transmettez si nécessaire.
(Bien que cela puisse provoquer des erreurs avec les chaînes, car elles ressemblent à des séquences.)
Un moyen simple de vérifier le type est de le comparer avec quelque chose dont vous connaissez le type.
>>> a = 1
>>> type(a) == type(1)
True
>>> b = 'abc'
>>> type(b) == type('')
True
Je pense que la meilleure façon est de bien taper vos variables. Vous pouvez le faire en utilisant la bibliothèque de "typage".
Exemple:
from typing import NewType
UserId = NewType ('UserId', int)
some_id = UserId (524313
) `
Vous pouvez vérifier avec la ligne ci-dessous pour vérifier de quel type de caractère la valeur donnée est:
def chr_type(chrx):
if chrx.isalpha()==True:
return 'alpha'
elif chrx.isdigit()==True:
return 'numeric'
else:
return 'nothing'
chr_type("12)