488 votes

Python: vérifie si un objet est une liste ou un tuple (mais pas une chaîne de caractères)

C'est ce que je fais normalement pour vérifier que l'entrée est un list / tuple - mais pas un str . Parce que plusieurs fois je suis tombé sur des bogues où une fonction passe un objet str par erreur, et la fonction cible fait for x in lst supposant que lst est en fait un list ou tuple .

 assert isinstance(lst, (list, tuple))
 

Ma question est la suivante: existe-t-il un meilleur moyen d'y parvenir?

329voto

Nick Craig-Wood Points 18742

je pense

 assert not isinstance(lst, basestring)
 

Est ce que vous voulez réellement, sinon vous manquerez beaucoup de choses qui agissent comme des listes, mais ne sont pas des sous-classes de list ou tuple .

175voto

steveha Points 24808

Rappelez-vous qu'en Python on veut utiliser "duck typing". Donc, tout ce qui agit comme une liste peut être considérée comme une liste. Donc, ne pas vérifier le type d'une liste, il suffit de voir si elle agit comme une liste.

Mais les chaînes de loi comme une liste trop, et souvent ce n'est pas ce que nous voulons. Il y a des moments où il est même un problème! Donc, vérifier explicitement pour une chaîne de caractères, mais ensuite utiliser duck-typing.

Voici une fonction que j'ai écrit pour le plaisir. C'est une version spéciale de l' repr() qui imprime toute la séquence dans les crochets ('<', '>').

def srepr(arg):
    if isinstance(arg, basestring): # Python 3: isinstance(arg, str)
        return repr(arg)
    try:
        return '<' + ", ".join(srepr(x) for x in arg) + '>'
    except TypeError: # catch when for loop fails
        return repr(arg) # not a sequence so just return repr

C'est propre et élégant, ensemble. Mais qu'est-ce que isinstance() vérifier en train de faire là? C'est une sorte de hack. Mais il est essentiel.

Cette fonction s'appelle elle-même de manière récursive sur tout ce qui agit comme une liste. Si nous n'avons pas la poignée de la chaîne spécialement, alors il sera traité comme une liste, et de séparer les caractères un à un. Mais alors l'appel récursif voudrais essayer de traiter chaque caractère comme une liste, et cela fonctionne! Même une chaîne de caractères fonctionne comme une liste! La fonction serait de les garder sur l'appel lui-même de manière récursive jusqu'à ce débordement de pile.

Des fonctions comme celle-ci, qui dépendent de chaque appel récursif de casser le travail à faire, avoir spéciales aux chaînes--parce que vous ne pouvez pas briser une chaîne de caractères au-dessous du niveau d'une chaîne de caractères, et même une chaîne de caractères agit comme une liste.

Remarque: l' try/except est la façon la plus propre à exprimer nos intentions. Mais si ce code était en quelque sorte le temps critique, on peut vouloir le remplacer par une sorte de test pour voir si arg est une séquence. Plutôt que de tester le type, nous devrions sans doute une analyse des comportements. Si il a un .strip() méthode, c'est une chaîne, afin de ne pas les considérer comme une séquence; si, au contraire, il est indexable ou itératif, c'est une séquence:

def is_sequence(arg):
    return (not hasattr(arg, "strip") and
            hasattr(arg, "__getitem__") or
            hasattr(arg, "__iter__"))

def srepr(arg):
    if is_sequence(arg):
        return '<' + ", ".join(srepr(x) for x in arg) + '>'
    return repr(arg)

EDIT: j'ai d'abord écrit ci-dessus avec un chèque de __getslice__() mais j'ai remarqué que dans l' collections documentation du module, la méthode intéressante est l' __getitem__(), ce qui fait sens, c'est la façon dont vous l'index d'un objet. Celui qui semble le plus fondamental qu' __getslice__() j'ai donc changé le ci-dessus.

126voto

H = "Hello"

if type(H) is list or type(H) is tuple:
    ## Do Something.
else
    ## Do Something.

41voto

Cesar Points 2079

Python avec la saveur de PHP:

 def is_array(var):
    return isinstance(var, (list, tuple))
 

11voto

Robert Rossney Points 43767

Généralement parlant, le fait qu'une fonction qui effectue une itération sur un objet de travaux sur cordes ainsi que les tuples et les listes est caractéristique de plus de bug. Très certainement, vous pouvez utiliser isinstance ou de canard à taper pour vérifier un argument, mais pourquoi devriez-vous?

Qui sonne comme une question rhétorique, mais il ne l'est pas. La réponse à "pourquoi devrais-je vérifier l'argument du type?" est probablement va proposer une solution au vrai problème, pas le problème perçu. Pourquoi est-ce un bug lorsqu'une chaîne est passée à la fonction? Aussi: si c'est un bug lorsqu'une chaîne est passée à cette fonction, est-il aussi un bug si certains d'autres non, liste, tuple itérable est passé? Pourquoi ou pourquoi pas?

Je pense que la réponse la plus fréquente à la question est susceptible d'être que les développeurs qui écrivent f("abc") attendons à ce que la fonction de se comporter comme s'ils avaient écrit des f(["abc"]). Il y a probablement des circonstances où il fait plus de sens pour protéger les développeurs d'eux-mêmes qu'il n'en faut pour soutenir le cas d'utilisation de l'itération à travers les caractères dans une chaîne. Mais j'avais penser à long et dur sur la première.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X