N'oubliez pas qu'en Python, nous voulons utiliser le "typage du canard". Ainsi, tout ce qui agit comme une liste peut être traité comme une liste. Donc, ne vérifiez pas le type d'une liste, voyez simplement si elle agit comme une liste.
Mais les chaînes agissent également comme une liste, et souvent ce n'est pas ce que nous voulons. Il y a des moments où c'est même un problème! Donc, recherchez explicitement une chaîne, mais utilisez ensuite la frappe de canard.
Voici une fonction que j'ai écrite pour le plaisir. Il s'agit d'une version spéciale repr()
qui imprime toute séquence entre 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, dans l'ensemble. Mais que fait ce isinstance()
chèque là-bas? C'est une sorte de hack. Mais c'est essentiel.
Cette fonction s'appelle récursivement sur tout ce qui agit comme une liste. Si nous ne gérions pas la chaîne spécialement, elle serait traitée comme une liste et divisée un caractère à la fois. Mais alors l'appel récursif essaierait de traiter chaque personnage comme une liste - et cela fonctionnerait! Même une chaîne à un caractère fonctionne comme une liste! La fonction continuerait à s'appeler récursivement jusqu'au débordement de la pile.
Les fonctions comme celle-ci, qui dépendent de chaque appel récursif décomposant le travail à effectuer, doivent avoir des chaînes de cas spécial - car vous ne pouvez pas décomposer une chaîne en dessous du niveau d'une chaîne à un caractère, et même une La chaîne de caractères agit comme une liste.
Remarque: le try
/ except
est le moyen le plus propre d'exprimer nos intentions. Mais si ce code était en quelque sorte critique dans le temps, nous pourrions vouloir le remplacer par une sorte de test pour voir s'il arg
s'agit d'une séquence. Plutôt que de tester le type, nous devrions probablement tester les comportements. S'il a une .strip()
méthode, c'est une chaîne, alors ne la considérez pas comme une séquence; sinon, si elle est indexable ou itérable, 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 écrit à l'origine ce qui précède avec une vérification, __getslice__()
mais j'ai remarqué que dans la collections
documentation du module, la méthode intéressante est __getitem__()
; c'est logique, c'est ainsi que vous indexez un objet. Cela semble plus fondamental que __getslice__()
j'ai donc changé ce qui précède.