Tester si une variable est une liste ou un tuple

234

En python, quelle est la meilleure façon de tester si une variable contient une liste ou un tuple? (c.-à-d. une collection)

Est-ce isinstance()aussi mal que suggéré ici? http://www.canonical.org/~kragen/isinstance/

Mise à jour: la raison la plus courante pour laquelle je veux distinguer une liste d'une chaîne est lorsque j'ai une arborescence imbriquée indéfiniment profonde / une structure de données de listes de listes de listes de chaînes, etc. que j'explore avec un algorithme récursif et dont j'ai besoin pour savoir quand j'ai touché les nœuds "feuilles".

interstar
la source
72
Rejeter largement la vérification de type comme un mal est un peu facile. Cela fait partie de la langue. Si c'est si mal, quelqu'un devrait écrire un PEP pour le retirer.
Adam Crossland
4
@Adam Crossland: "Cela fait partie de la langue." Tout comme la division par zéro. C'est évitable. Dans ce cas, sans informations supplémentaires, c'est probablement complètement inutile. La plupart des vérifications de type en Python sont inutiles. Comme tout n'est pas inutile, une vérification de type doit être présente. Mais cela ne signifie pas que c'est utile, précieux ou même une bonne idée.
S.Lott
11
Vous dites donc qu'une vérification de type est nécessaire, mais malgré cela, c'est inutile, sans valeur et une mauvaise idée. Désolé, cela n'a tout simplement pas de sens.
Glenn Maynard
18
Le "XXX est mauvais" est mal conçu, un raccourci trompeur pour "la façon dont vous demandez de faire XXX suggère que vous ne comprenez pas quand il doit être utilisé, et vous voulez presque certainement autre chose". C'est très probablement le cas ici.
Glenn Maynard du
2
Je ne l'ai pas largement rejeté comme étant mauvais. J'ai écrit un court essai sur quand c'est mal et quand c'est justifiable. Cet essai peut être beaucoup de choses - correct, faux, clair, vague, agréable, ennuyeux - mais une chose qu'il n'est pas est un large rejet de la technique.
Kragen Javier Sitaker

Réponses:

101

Allez-y et utilisez isinstancesi vous en avez besoin. C'est un peu mal, car il exclut les séquences personnalisées, les itérateurs et autres choses dont vous pourriez avoir besoin. Cependant, vous devez parfois vous comporter différemment si quelqu'un, par exemple, passe une chaîne. Ma préférence serait de vérifier explicitement strou unicodecomme ceci:

import types
isinstance(var, types.StringTypes)

NB Ne confondez pas types.StringTypepour types.StringTypes. Ce dernier intègre stret unicodeobjets.

Le typesmodule est considéré par beaucoup comme obsolète en faveur de la vérification directe par rapport au type de l'objet, donc si vous préférez ne pas utiliser ce qui précède, vous pouvez également vérifier explicitement stret unicode, comme ceci:

isinstance(var, (str, unicode)):

Éditer:

Mieux vaut encore:

isinstance(var, basestring)

Fin de la modification

Après l'un ou l'autre de ces éléments, vous pouvez vous remettre à vous comporter comme si vous obteniez une séquence normale, laissant les non-séquences lever des exceptions appropriées.

Voyez ce qui est "mal" à propos de la vérification de type, ce n'est pas que vous souhaitiez peut-être vous comporter différemment pour un certain type d'objet, c'est que vous limitez artificiellement votre fonction de faire la bonne chose avec des types d'objet inattendus qui autrement feraient la bonne chose. Si vous avez une solution de secours finale qui n'est pas vérifiée par type, vous supprimez cette restriction. Il convient de noter que trop de vérification de type est une odeur de code qui indique que vous voudrez peut-être effectuer une refactorisation, mais cela ne signifie pas nécessairement que vous devriez l'éviter du getgo.

jcdyer
la source
2
Le module types est un peu un artefact historique. Comme mentionné sur docs.python.org/dev/library/types.html#module-types si vous devez vraiment vérifier le strtype, vous devez simplement l'utiliser directement, au lieu d'utiliser types.StringTypece qui n'est qu'un alias. Mais je ne pense pas que cette réponse réponde à la question posée, car il s'agissait "d'une collection". À moins que vous n'utilisiez un python suffisamment nouveau pour avoir le abcmodule qui n'est pas quelque chose que vous pouvez utiliser isinstancepour vérifier, et même dans ce cas, je recommanderais d'éviter la vérification si possible.
mzz
1
assert isinstance(u'abc', str) == False. Je suis d'accord qu'il vaut mieux comparer directement le type, plutôt que d'utiliser le typesmodule, mais types.StringTypesfait quelque chose qui strne le fait pas: il retourne True for stret unicodeobjets. Je vais modifier ma réponse pour proposer une double vérification comme alternative.
jcdyer
1
Je me rends compte que je n'ai pas répondu directement à la question de la vérification des collections, mais la vraie question posée était "Est-ce le isinstancemal?" Et j'ai donné un contre-exemple qui (1) est une utilisation non malveillante isinstance, car avoir un repli signifie qu'il ne casse pas le typage de canard, et (2) est une bonne solution pour une motivation très courante que les gens ont pour vouloir vérifier si quelque chose est un listou tuple(c'est-à-dire pour les lever des ambiguïtés des chaînes).
jcdyer
Je suis d'accord, avec la mise en garde qu'il est souvent utile que les types personnalisés se comportent également comme des chaînes. Mais l'OO de Python ne va que si loin ...
Kragen Javier Sitaker
Est - class Foo(str): passce que vous voulez?
jcdyer
568
if type(x) is list:
    print 'a list'
elif type(x) is tuple:
    print 'a tuple'
else:
    print 'neither a tuple or a list'
wall-e
la source
1
Ne semble pas fonctionner: type ([]) ==> liste; type ([]) est list ===> False
sten
3
En Python 2.7.5: type([]) is listretoursTrue
David Geiger
54
type(x) in [list,tuple]est plus court.
Alex Holcombe
si x et type (x) est la liste: pour éviter le décalage []
Kenichi Shibata
J'ai dû tellement défiler vers le bas. : D
Rithwik
38

Il n'y a rien de mal à l'utiliser isinstancetant qu'il n'est pas redondant. Si une variable ne doit être qu'une liste / tuple, documentez l'interface et utilisez-la comme telle. Sinon, un chèque est parfaitement raisonnable:

if isinstance(a, collections.Iterable):
    # use as a container
else:
    # not a container!

Ce type de vérification a de bons cas d'utilisation, comme avec la méthode standard commence par / fin avec les méthodes (bien que pour être précis, elles soient implémentées en C dans CPython en utilisant une vérification explicite pour voir s'il s'agit d'un tuple - il y a plus d'une façon pour résoudre ce problème, comme mentionné dans l'article auquel vous liez).

Une vérification explicite est souvent meilleure que d'essayer d'utiliser l'objet comme conteneur et de gérer l'exception - ce qui peut provoquer toutes sortes de problèmes avec l'exécution partielle ou inutile du code.

Scott Griffiths
la source
15
C'est une bonne façon de vérifier si une variable est itérable. Cependant, cela ne fonctionnera probablement pas aux fins de cette question. Sachez qu'une chaîne est également itérable et créerait probablement un faux positif.
Corey O.
Un setobjet est également un itérable, ce qui signifie que même si vous pouvez sûrement en extraire des éléments, mais il ne garantit pas un certain ordre, ce qui est très dangereux pour certains algorithmes. Dans les cas où la commande des éléments est importante, un algorithme utilisant cet extrait pourrait potentiellement générer des résultats différents sur différentes exécutions!
koo
14

Documentez l'argument comme devant être une séquence et utilisez-le comme une séquence. Ne cochez pas le type.

Ignacio Vazquez-Abrams
la source
12

Que diriez-vous hasattr(a, "__iter__"):?

Il indique si l'objet retourné peut être itéré en tant que générateur. Par défaut, les tuples et les listes le peuvent, mais pas les types de chaînes.

user1914881
la source
j'ai trouvé cela vraiment utile.
javadba
8
Donne également la valeur True pour les chaînes (au moins sur Python 3).
SzieberthAdam
2
C'est une mauvaise réponse. Puisque le type 'str' a également la méthode ' iter '. @SzieberthAdam avait raison. Le type 'set' est également itérable, mais n'est pas ordonnable.
PADYMKO
Les condamnés aussi __iter__.
Thet
Si vous continuez, n'importe quel type personnalisé peut avoir __iter__pour une raison quelconque ...
Alexander Irbis
10

Sur les type(list) is listretours Python 2.8, false
je suggère de comparer le type de cette manière horrible:

if type(a) == type([]) :
  print "variable a is a list"

(enfin au moins sur mon système, en utilisant anaconda sur Mac OS X Yosemite)

Xanderite
la source
1
Est-ce que le type (a) est list aussi faux?
Dmitriy Sintsov
4
Voulez-vous dire Python 2.7.8? python.org/dev/peps/pep-0404/#official-pronouncement
Carl
Bonjour, je suis curieux: Pourquoi considérez-vous votre exemple "horrible"?
Seth Connell
type(list) is listretours Falseparce type(list)est type, non list. type(list()) is listou avec toute autre instance d'une liste reviendra True.
Michael Greene
8

Python utilise le "Duck typing", c'est-à-dire que si une variable kwaks comme un canard, ce doit être un canard. Dans votre cas, vous voulez probablement qu'il soit itérable, ou vous voulez accéder à l'élément à un certain index. Vous devriez juste faire ceci: c'est-à-dire utiliser l'objet dans for var:ou à l' var[idx]intérieur d'un trybloc, et si vous obtenez une exception, ce n'était pas un canard ...

Wim
la source
7
Le problème est que si varune itération de chaîne se produira avec des résultats probablement inattendus.
Brian M. Hunt
Malgré le fait déclaré par Brian M. Hunt, c'est une solution assez pythonique, en termes de demande de pardon plutôt que de permission.
Géza Török
6
>>> l = []
>>> l.__class__.__name__ in ('list', 'tuple')
True
tetra5
la source
3

Si vous avez juste besoin de savoir si vous pouvez utiliser la foo[123]notation avec la variable, vous pouvez vérifier l'existence d'un __getitem__attribut (qui est ce que python appelle lorsque vous accédez par index) avechasattr(foo, '__getitem__')

Geoff Reedy
la source
2

Doit être un test plus complexe si vous voulez vraiment gérer à peu près n'importe quoi comme argument de fonction.

type(a) != type('') and hasattr(a, "__iter__")

Bien que, généralement, il suffit de préciser qu'une fonction s'attend à être itérable et de ne vérifier que type(a) != type('') .

Il peut également arriver que pour une chaîne, vous ayez un chemin de traitement simple ou que vous soyez gentil et fassiez un fractionnement, etc., donc vous ne voulez pas crier sur les chaînes et si quelqu'un vous envoie quelque chose de bizarre, laissez-le simplement une exception.

ZXX
la source
2

Un autre moyen simple de savoir si une variable est une liste ou un tuple ou de vérifier généralement le type de variable serait:

    def islist(obj):

        if ("list" in str(type(obj)) ): return True

        else : return False
mahdi omidiyan
la source
1

En principe, je suis d'accord avec Ignacio, ci-dessus, mais vous pouvez également utiliser type pour vérifier si quelque chose est un tuple ou une liste.

>>> a = (1,)
>>> type(a)
(type 'tuple')
>>> a = [1]
>>> type(a)
(type 'list')
Adam Crossland
la source