En python, quel est le meilleur moyen de vérifier si une variable contient une liste ou un tuple? (c.-à-d. une collection)
Est-ce que isinstance()
est aussi pervers que suggéré ici? http://www.canonical.org/~kragen/isinstance/
Mise à jour: la raison la plus courante pour laquelle je souhaite distinguer une liste d'une chaîne est lorsque j'ai une structure imbriquée d'arbre/de données indéfiniment profonde/de listes de listes de chaînes 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 "feuille".
Allez-y et utilisez isinstance
si vous en avez besoin. C'est un peu diabolique, car il exclut les séquences personnalisées, les itérateurs et d'autres éléments dont vous pourriez avoir réellement besoin. Cependant, vous devez parfois vous comporter différemment si, par exemple, quelqu'un passe une chaîne. Ma préférence serait de vérifier explicitement str
ou unicode
comme ceci:
import types
isinstance(var, types.StringTypes)
N.B. Ne confondez pas types.StringType
avec types.StringTypes
. Ce dernier intègre les objets str
et unicode
.
Nombreux sont ceux qui considèrent que le module types
est obsolète et ne permet que de vérifier directement le type d'objet. Par conséquent, si vous préférez ne pas utiliser ce qui précède, vous pouvez également effectuer une recherche explicite sur str
et unicode
, comme ceci:
isinstance(var, (str, unicode)):
Edit:
Mieux vaut encore:
isinstance(var, basestring)
Fin éditer
Ensuite, vous pouvez vous comporter comme si vous obteniez une séquence normale, laissant les non-séquences lever les exceptions appropriées.
Voir ce qui est "pervers" dans la vérification de type n’est pas que vous souhaitiez peut-être vous comporter différemment pour un certain type d’objet, c’est que vous empêchez artificiellement votre fonction de faire la bonne chose avec des types d’objets inattendus qui feraient autrement la bonne chose. Si vous disposez d'une solution de secours finale non vérifiée, 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.
if type(x) is list:
print 'a list'
Elif type(x) is Tuple:
print 'a Tuple'
else:
print 'neither a Tuple or a list'
Il n'y a rien de mal à utiliser isinstance
tant que ce n'est pas redondant. Si une variable ne doit être qu'une liste/un tuple, alors documentez l'interface et utilisez-la simplement. 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 startswith / endswith vérification explicite pour voir s’il s’agit d’un tuple - il existe plus d’une façon de résoudre ce problème, comme indiqué dans l’article auquel vous créez un lien).
Une vérification explicite est souvent préférable à une tentative d'utilisation de l'objet en tant que conteneur et à la gestion de l'exception, ce qui peut entraîner toutes sortes de problèmes lorsque le code est exécuté partiellement ou inutilement.
Documentez l'argument comme devant être une séquence et utilisez-le comme une séquence. Ne vérifie pas le type.
Que diriez-vous de: hasattr(a, "__iter__")
?
Il indique si l'objet renvoyé peut être itéré en tant que générateur. Par défaut, les n-uplets et les listes peuvent, mais pas les types de chaîne.
On Python 2.8 type(list) is list
renvoie false
Je suggérerais de comparer le type de cette façon 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)
Python utilise "Duck Typing", c'est-à-dire si une variable kwaks ressemble à un canard, il doit s'agir d'un canard. Dans votre cas, vous voulez probablement que ce soit itératif, ou vous voulez accéder à l'élément à un certain index. Vous devriez simplement faire ceci: c'est-à-dire utiliser l'objet dans for var:
ou var[idx]
à l'intérieur d'un bloc try
, et si vous obtenez une exception ce n'est pas un canard ...
>>> l = []
>>> l.__class__.__in ('list', 'Tuple')
True
Si vous avez juste besoin de savoir si vous pouvez utiliser la notation foo[123]
avec la variable, vous pouvez vérifier l'existence d'un attribut __getitem__
(qui est ce que python appelle lorsque vous accédez à par index) avec hasattr(foo, '__getitem__')
En principe, je suis d'accord avec Ignacio ci-dessus, mais vous pouvez aussi 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')
Le test doit être plus complexe si vous voulez vraiment gérer n'importe quoi comme argument de fonction.
type(a) != type('') and hasattr(a, "__iter__")
Bien qu’il soit généralement suffisant de préciser qu’une fonction s’attend à ce qu’il soit itératif et de ne cocher que type(a) != type('')
.
En outre, il peut arriver que, pour une chaîne, vous ayez un chemin de traitement simple ou que vous deveniez Nice et que vous fassiez une scission, etc. une exception.
Un autre moyen simple de savoir si une variable est une liste, un tuple ou généralement un type de variable de contrôle est le suivant:
def islist(obj):
if ("list" in str(type(obj)) ): return True
else : return False