5 votes

Meilleur moyen de distinguer entre les arguments scalaire, liste et dictionnaire en Python?

Je veux une fonction qui prend normalement un argument de type X où X est soit un scalaire, une liste, ou un dictionnaire, et renvoie une liste de X avec les mêmes valeurs clés, basée sur d'autres informations.

def foo(info, k):
   return [bar(item,k) for item in processInfo(info)]

def bar(item, keydata):
   # pseudo-code suit.
   # Ce que nous voulons faire est renvoyer une sortie de type parallèle à la clé d'entrée k,
   # en utilisant les données clés pour rechercher des informations de l'élément d'entrée.
   if keydata est un scalaire:
      return item[keydata]
   elif keydata est une liste:
      return [item[k] for k in keydata]
   elif keydata est un dictionnaire:
      return dict((k,item[v]) for (k,v) in keydata.iteritems())
   else:
      raise ValueError('bar attend un scalaire, une liste ou un dictionnaire')

Ma question est, comment puis-je dispatcher entre les trois types?


éditer: Une chaîne de caractères doit être interprétée comme un scalaire, pas une liste/itérable. Les tuples doivent être interprétés comme itérables.

éditer 2: Je veux un typage canard, pas un typage strict.

5voto

Mark Ransom Points 132545

Vous devez faire les choses dans le bon ordre car les types str et dict sont itérables.

from collections import Iterable, Mapping  # en python 3, utiliser from collections.abc

def bar(item, keydata):
    if isinstance(keydata, Mapping):
        return {k: item[v] for (k,v) in keydata.iteritems()}
    elif isinstance(keydata, Iterable) and not isinstance(keydata, str):
        return [item[k] for k in keydata]
    return item[keydata]

3voto

Felipe Points 626

Cela dépend de la rigueur avec laquelle vous souhaitez traiter votre entrée. L'approche isinstance vous oblige à spécifier les types à accepter (c’est-à-dire pas de duck typing). Cela fonctionne tant que vos utilisateurs ne passent que ces classes ou des sous-types de ces classes. Vous pouvez également essayer de distinguer les paramètres par les méthodes qu'ils supportent. Un exemple serait

Éditer : ajout du cas spécial pour les chaînes de caractères

if isinstance(keydata, basestring):
    # cas spécial pour éviter de considérer les chaînes de caractères comme des conteneurs
    # pour python 3.x utilisez str au lieu de basestring
    return item[keydata]
try:
    return dict((k,item[v]) for (k,v) in keydata.iteritems())
except AttributeError:
    # ce n'est pas un objet de type dict
    pass
try:
    return [item[k] for k in keydata]
except TypeError:
    # ce n'est pas itérable
return item[keydata]

Le choix du flux de contrôle dépend de la flexibilité que vous souhaitez avoir, ainsi que de la manière dont vous souhaitez gérer les cas ambigus. Par exemple, une chaîne de caractères est-elle considérée comme une séquence de caractères ou un scalaire?

2voto

Meitham Points 1872

Utilisez les nouveaux trucs sympas :) en important collections

>>> isinstance([], collections.Sequence)
True
>>> isinstance({}, collections.Mapping)
True

Vous devriez également envisager de consulter le module types

0voto

Joran Beasley Points 28451
si isinstance(keydata,(int,float,str)): #scalaire

elif isinstance(keydata,(list,tuple)):#itérable

elif isinstance(keydata,dict):#dictionnaire

peut-être?? (je manque probablement quelques types)...

0voto

nacholibre Points 528

Ou vous pouvez utiliser type, mais isinstance est recommandé selon http://docs.python.org/2/library/functions.html#type

if type(asd) in (int, str):
    print 'asd est int ou str'

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