Existe-t-il un moyen simple de déterminer si une variable est une liste, un dictionnaire ou autre chose? Je récupère un objet qui peut être de l'un ou de l'autre type et je dois pouvoir faire la différence.
python
dictionary
types
typeof
Justin Ethier
la source
la source
try
n'aide pas. Par exemple, si vous saviez qu'un utilisateur pouvait passer une chaîne ou un tableau, les deux sont indexables, mais cet index signifie quelque chose de complètement différent. S'appuyer simplement sur un essai dans ces cas échouera de manière inattendue et étrange. Une solution consiste à créer une méthode distincte, une autre à ajouter une petite vérification de type. Personnellement, je préfère le comportement polymorphe à plusieurs méthodes qui font presque la même chose ... mais c'est juste moi :)Réponses:
Il existe deux fonctions intégrées qui vous aident à identifier le type d'un objet. Vous pouvez utiliser
type()
si vous avez besoin du type exact d'un objet etisinstance()
pour comparer le type d'un objet avec quelque chose. Habituellement, vous souhaitez utiliser laisistance()
plupart du temps car il est très robuste et prend également en charge l'héritage de types.Pour obtenir le type réel d'un objet, vous utilisez la
type()
fonction intégrée. Le passage d'un objet comme seul paramètre renvoie l'objet type de cet objet:Bien sûr, cela fonctionne également pour les types personnalisés:
Notez que
type()
ne renverra que le type immédiat de l'objet, mais ne pourra pas vous parler de l'héritage de type.Pour couvrir cela, vous devez utiliser la
isinstance
fonction. Bien sûr, cela fonctionne également pour les types intégrés:isinstance()
est généralement le moyen préféré pour garantir le type d'un objet car il accepte également les types dérivés. Donc, sauf si vous avez réellement besoin de l'objet type (pour une raison quelconque), l'utilisationisinstance()
est préférable àtype()
.Le deuxième paramètre de
isinstance()
accepte également un tuple de types, il est donc possible de vérifier plusieurs types à la fois.isinstance
retournera alors true, si l'objet est de l'un de ces types:la source
is
au lieu de==
car les types sont des singletonsisinstance
est de toute façon la forme préférée, donc ni l'un==
ni l' autre neis
doit être utilisé.type
est la meilleure réponse. Il y a des moments oùisinstance
est la meilleure réponse et il y a des moments où la frappe de canard est la meilleure réponse. Il est important de connaître toutes les options afin de pouvoir choisir celle qui convient le mieux à la situation.type(foo) is SomeType
serait mieux queisinstance(foo, SomeType)
.isinstance
pour votre cas d'utilisation (vérifier une gamme de types), et avec aussi une syntaxe propre, qui a le grand avantage que vous pouvez capturer des sous-classes. quelqu'un utilisantOrderedDict
détesterait que votre code échoue car il accepte simplement les dict purs.Vous pouvez le faire en utilisant
type()
:la source
Il pourrait être plus Pythonic d'utiliser un bloc
try
....except
De cette façon, si vous avez une classe qui caquette comme une liste, ou charlatans comme un dict, il se comportera correctement quel que soit son type vraiment est.Pour clarifier, la méthode préférée pour "faire la différence" entre les types de variables est avec quelque chose appelé typage du canard : tant que les méthodes (et les types de retour) auxquels une variable répond sont celles attendues par votre sous-programme, traitez-la comme ce que vous attendez d'elle être. Par exemple, si vous avez une classe qui surcharge les opérateurs de parenthèses avec
getattr
etsetattr
, mais utilise un schéma interne amusant, il serait approprié qu'elle se comporte comme un dictionnaire si c'est ce qu'elle essaie d'émuler.L'autre problème avec la
type(A) is type(B)
vérification est que siA
est une sous-classe deB
, elle évaluefalse
quand, par programme, vous espérez qu'elle le soittrue
. Si un objet est une sous-classe d'une liste, il devrait fonctionner comme une liste: la vérification du type tel que présenté dans l'autre réponse évitera cela. (isinstance
fonctionnera cependant).la source
try
...except
est une bonne solution lorsque vous souhaitez gérer les erreurs, mais pas lorsque vous décidez d'un comportement basé sur le type.Sur les instances d'objet, vous avez également:
attribut. Voici un exemple extrait de la console Python 3.3
Attention, dans python 3.x et dans les classes New-Style (disponibles en option à partir de Python 2.6), la classe et le type ont été fusionnés et cela peut parfois conduire à des résultats inattendus. Principalement pour cette raison, ma façon préférée de tester les types / classes est la fonction intégrée intégrée.
la source
__class__
est généralement OK sur Python 2.x, les seuls objets en Python qui n'ont pas d'__class__
attribut sont les classes anciennes AFAIK. Soit dit en passant, je ne comprends pas votre préoccupation concernant Python 3 - sur une telle version, juste chaque objet a un__class__
attribut qui pointe vers la classe appropriée.Déterminer le type d'un objet Python
Déterminez le type d'un objet avec
type
Bien que cela fonctionne, évitez les attributs de soulignement double comme
__class__
- ils ne sont pas sémantiquement publics, et, même si ce n'est peut-être pas le cas dans ce cas, les fonctions intégrées ont généralement un meilleur comportement.vérification de type
Eh bien, c'est une question différente, n'utilisez pas de type - utilisez
isinstance
:Cela couvre le cas où votre utilisateur pourrait faire quelque chose d'intelligent ou de sensible en sous
str
- classant - selon le principe de la substitution de Liskov, vous voulez pouvoir utiliser des instances de sous-classe sans casser votre code - etisinstance
prend en charge cela.Utiliser des abstractions
Encore mieux, vous pouvez rechercher une classe de base abstraite spécifique à partir de
collections
ounumbers
:Ou tout simplement ne pas vérifier explicitement le type
Ou, peut-être mieux encore, utilisez la frappe de canard et ne vérifiez pas explicitement votre code. Duck-typing soutient Liskov Substitution avec plus d'élégance et moins de verbosité.
Conclusion
type
d'obtenir réellement la classe d'une instance.isinstance
de vérifier explicitement les sous-classes réelles ou les abstractions enregistrées.la source
try
/except
au lieu de vérifier explicitement.Vous pouvez utiliser
type()
ouisinstance()
.Soyez averti que vous pouvez clobber
list
ou tout autre type en affectant une variable dans la portée actuelle du même nom.Ci-dessus, nous voyons que cela
dict
est réaffecté à une chaîne, donc le test:...échoue.
Pour contourner cela et utiliser
type()
avec plus de prudence:la source
dict
chaîne échouera également pour de nombreux autres codes, commedict([("key1", "value1"), ("key2", "value2")])
. La réponse pour ce genre de problèmes est "Alors ne fais pas ça" . N'obscurcissez pas les noms de types intégrés et ne vous attendez pas à ce que les choses fonctionnent correctement.Bien que les questions soient assez anciennes, je suis tombé dessus tout en trouvant moi-même un moyen approprié, et je pense qu'il faut encore clarifier, au moins pour Python 2.x (n'a pas vérifié Python 3, mais puisque le problème se pose avec les classes classiques qui ont disparu sur une telle version, cela n'a probablement pas d'importance).
Ici, j'essaie de répondre à la question du titre: comment puis-je déterminer le type d'un objet arbitraire ? D'autres suggestions sur l'utilisation ou la non-utilisation de l'instance sont bonnes dans de nombreux commentaires et réponses, mais je ne réponds pas à ces préoccupations.
Le principal problème avec l'
type()
approche est qu'elle ne fonctionne pas correctement avec les instances à l'ancienne :L'exécution de cet extrait donnerait:
Ce qui, selon moi, n'est pas ce à quoi la plupart des gens s'attendraient.
L'
__class__
approche est la plus proche de l'exactitude, mais elle ne fonctionnera pas dans un cas crucial: lorsque l'objet transmis est une classe à l' ancienne (pas une instance!), Car ces objets n'ont pas un tel attribut.C'est le plus petit extrait de code auquel je pourrais penser qui répond à une telle question légitime de manière cohérente:
la source
soyez prudent en utilisant isinstance
mais tapez
la source
En marge des réponses précédentes, il convient de mentionner l'existence de
collections.abc
plusieurs classes de base abstraites (ABC) qui complètent le typage canard.Par exemple, au lieu de vérifier explicitement si quelque chose est une liste avec:
vous pourriez, si vous êtes seulement intéressé à voir si l'objet que vous avez permet d'obtenir des objets, utilisez
collections.abc.Sequence
:si vous êtes strictement intéressé par les objets qui permettent d'obtenir, de définir et de supprimer des éléments (c'est-à-dire des séquences mutables ), vous opterez pour
collections.abc.MutableSequence
.Beaucoup d' autres y sont définis ABCs,
Mapping
pour les objets qui peuvent être utilisés comme cartes,Iterable
,Callable
, et ainsi de suite. Une liste complète de tous ces éléments peut être consultée dans la documentation decollections.abc
.la source
En général, vous pouvez extraire une chaîne d'un objet avec le nom de classe,
et l'utiliser à des fins de comparaison,
la source
Dans de nombreux cas pratiques, au lieu d'utiliser
type
ouisinstance
vous pouvez également utiliser@functools.singledispatch
, qui est utilisé pour définir des fonctions génériques ( fonction composée de plusieurs fonctions implémentant la même opération pour différents types ).En d'autres termes, vous voudriez l'utiliser lorsque vous avez un code comme celui-ci:
Voici un petit exemple de son fonctionnement:
De plus, nous pouvons utiliser des classes abstraites pour couvrir plusieurs types à la fois:
la source
type()
est une meilleure solution queisinstance()
, notamment pourbooleans
:True
et neFalse
sont que des mots clés qui signifient1
et0
en python. Donc,et
les deux reviennent
True
. Les deux booléens sont une instance d'un entier.type()
, cependant, est plus intelligent:retourne
False
.la source