web-dev-qa-db-fra.com

Quel est le meilleur moyen (idiomatique) de vérifier le type d'une variable Python?

J'ai besoin de savoir si une variable dans Python est une chaîne ou un dict. Y at-il quelque chose de mal avec le code suivant?

if type(x) == type(str()):
    do_something_with_a_string(x)
Elif type(x) == type(dict()):
    do_somethting_with_a_dict(x)
else:
    raise ValueError

Mise à jour: J'ai accepté la réponse d'avisser (bien que je changerai d'avis si quelqu'un explique pourquoi isinstance est préférable à type(x) is).

Mais merci à nakedfanatic de m'avoir rappelé qu'il est souvent plus simple d'utiliser un dict (en tant qu'affirmation de cas) qu'une série if/Elif/else.

Laissez-moi élaborer sur mon cas d'utilisation. Si une variable est une chaîne, je dois la mettre dans une liste. Si c'est un dict, j'ai besoin d'une liste des valeurs uniques. Voici ce que je suis venu avec:

def value_list(x):
    cases = {str: lambda t: [t],
             dict: lambda t: list(set(t.values()))}
    try:
        return cases[type(x)](x)
    except KeyError:
        return None

Si vous préférez isinstance, comment écririez-vous cette fonction value_list()?

291
Daryl Spitzer

Que se passe-t-il si quelqu'un passe une chaîne Unicode à votre fonction? Ou une classe dérivée de dict? Ou une classe implémentant une interface de type dict? Le code suivant couvre les deux premiers cas. Si vous utilisez Python 2.6, vous pouvez utiliser collections.Mapping au lieu de dict selon le ABC PEP .

_def value_list(x):
    if isinstance(x, dict):
        return list(set(x.values()))
    Elif isinstance(x, basestring):
        return [x]
    else:
        return None
_
318
Suraj

type(dict()) dit "créez un nouveau dict, puis déterminez quel est son type". C'est plus rapide de dire juste "dict". Mais si vous voulez juste vérifier le type, une manière plus idiomatique est isinstance(x, dict).

Notez que isinstance inclut également des sous-classes (merci Dustin ):

class D(dict):
    pass

d = D()
print("type(d) is dict", type(d) is dict)  # -> False
print("isinstance (d, dict)", isinstance(d, dict))  # -> True
57
Ken

les types intégrés dans Python ont des noms intégrés:

>>> s = "hallo"
>>> type(s) is str
True
>>> s = {}
>>> type(s) is dict
True

remarquez l'opérateur est. Cependant, la vérification du type (si vous voulez l'appeler ainsi) est généralement effectuée en encapsulant un test spécifique au type dans une clause try-except, car ce n'est pas vraiment le type de la variable qui est important, mais la possibilité de faire un certain test. quelque chose avec ou pas.

34
Albert Visser

isinstance est préférable au type car elle est également évaluée comme True lorsque vous comparez une instance d'objet à une super-classe, ce qui signifie que vous n'aurez jamais à mettre votre ancien code dans un cas spécial pour l'utiliser avec des sous-classes dict ou str.

Par exemple:

 >>> class a_dict(dict):
 ...     pass
 ... 
 >>> type(a_dict()) == type(dict())
 False
 >>> isinstance(a_dict(), dict)
 True
 >>> 

Bien sûr, il peut arriver que vous ne souhaitiez pas ce comportement dans certaines situations, mais elles sont, espérons-le, beaucoup moins courantes que celles dans lesquelles vous le souhaitez.

19
Dirk Stoop

Je pense que je vais opter pour la méthode de frappe au canard: "s’il marche comme un canard, il charrie comme un canard, c’est un canard". De cette façon, vous n'aurez plus à vous soucier de savoir si la chaîne est unicode ou ascii.

Voici ce que je vais faire:

In [53]: s='somestring'

In [54]: u=u'someunicodestring'

In [55]: d={}

In [56]: for each in s,u,d:
    if hasattr(each, 'keys'):
        print list(set(each.values()))
    Elif hasattr(each, 'lower'):
        print [each]
    else:
        print "error"
   ....:         
   ....:         
['somestring']
[u'someunicodestring']
[]

Les experts ici présents sont invités à commenter ce type d’utilisation du duktkting. Je l’utilise, mais je me suis familiarisé avec le concept exact qui le sous-tend récemment et je suis très enthousiaste à ce sujet. Je voudrais donc savoir s’il ya trop de travail à faire.

8
JV.

Je pense qu'il pourrait être préférable de faire

if isinstance(x, str):
    do_something_with_a_string(x)
Elif isinstance(x, dict):
    do_somethting_with_a_dict(x)
else:
    raise ValueError

2 formes alternatives, selon votre code l'un ou l'autre est probablement considéré comme meilleur que cela même. On est de ne pas regarder avant de sauter

try:
  one, two = tupleOrValue
except TypeError:
  one = tupleOrValue
  two = None

L'autre approche est celle de Guido et consiste en une surcharge de fonctions qui laisse votre code plus ouvert.

http://www.artima.com/weblogs/viewpost.jsp?thread=155514

6
Ed.

Vous voudrez peut-être vérifier typecheck. http://pypi.python.org/pypi/typecheck

Module de vérification de type pour Python

Ce paquet fournit de puissantes fonctionnalités de vérification typographique au moment de l’exécution pour les fonctions, méthodes et générateurs Python. Sans nécessiter de préprocesseur personnalisé ni de modification de la langue, le package typecheck permet aux programmeurs et aux ingénieurs d'assurance qualité de formuler des affirmations précises sur les entrées et les sorties de code.

3

Cela devrait fonctionner - alors non, il n'y a rien de mal avec votre code. Cependant, cela pourrait aussi être fait avec un dict:

{type(str()): do_something_with_a_string,
 type(dict()): do_something_with_a_dict}.get(type(x), errorhandler)()

Un peu plus concis et Pythonic ne dirais-tu pas?


Edit .. En tenant compte des conseils d'Avisser, le code fonctionne également comme ceci et est plus joli:

{str: do_something_with_a_string,
 dict: do_something_with_a_dict}.get(type(x), errorhandler)()
3
nakedfanatic

J'ai utilisé une approche différente:

from inspect import getmro
if (type([]) in getmro(obj.__class__)):
    # This is a list, or a subclass of...
Elif (type{}) in getmro(obj.__class__)):
    # This one is a dict, or ...

Je ne me souviens pas pourquoi j'ai utilisé cela à la place d'isinstance, bien que ...

1
Matthew Schinckel

*sigh*

Non, la vérification des arguments dans python n'est pas nécessaire. C'est jamais nécessaire.

Si votre code accepte une chaîne ou un objet dict, votre conception est endommagée.

Cela vient du fait que si vous ne connaissez pas déjà le type d'objet dans votre propre programme, vous faites déjà quelque chose de mal.

Le typececking nuit à la réutilisation du code et réduit les performances. Avoir une fonction qui effectue différentes choses selon le type d'objet transmis est sujet aux bogues et a un comportement plus difficile à comprendre et à maintenir.

Vous avez les options d'assainissement suivantes:

1) Créez une fonction unique_values qui convertit les dessins en listes de valeurs uniques:

def unique_values(some_dict):
    return list(set(some_dict.values()))

Faites que votre fonction suppose que l'argument passé est toujours une liste. De cette façon, si vous devez passer une chaîne à la fonction, il vous suffit de faire:

myfunction([some_string])

Si vous avez besoin de passer un dict, vous faites:

myfunction(unique_values(some_dict))

C’est votre meilleure option, c’est propre, facile à comprendre et à entretenir. Toute personne lisant immédiatement le code comprend ce qui se passe et vous n'avez pas à vérifier votre code.

2) Créez deux fonctions, une qui accepte les listes de chaînes et une qui accepte les dict. Vous pouvez appeler les uns les autres en interne, de la manière la plus pratique (myfunction_dict peut créer une liste de chaînes et appeler myfunction_list).

Dans tous les cas, ne pas taper sur le clavier. C'est complètement inutile et n'a que des inconvénients. Refacturez votre code à la place d'une manière que vous n'avez pas besoin de dactylographier. Vous n'obtenez que des avantages, à court et à long terme.

0
nosklo