Quel est le meilleur (idiomatiques) façon de vérifier le type d'une variable Python? [dupliquer]

StackOverflow https://stackoverflow.com/questions/378927

  •  22-08-2019
  •  | 
  •  

Question

    

Cette question a déjà une réponse ici:

         

Je dois savoir si une variable en 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 de avisser (bien que je vais changer d'avis si quelqu'un explique pourquoi isinstance est préféré au type(x) is)

Mais grâce à nakedfanatic pour me rappeler qu'il est souvent plus propre d'utiliser un dict (comme une déclaration de cas) que si un / Elif / série autre.

Permettez-moi de préciser mon cas d'utilisation. Si une variable est une chaîne, je dois le mettre dans une liste. Si c'est un dict, je 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 isinstance est préféré, comment voulez-vous écrire cette fonction value_list()?

Était-ce utile?

La solution

Qu'est-ce qui se passe si quelqu'un passe une chaîne unicode à votre fonction? Ou une classe dérivée de dict? Ou une classe qui implémente une interface comme dict? code suivant couvre deux premiers cas. Si vous utilisez Python 2.6, vous pouvez utiliser collections.Mapping au lieu de dict selon la ABC PEP .

def value_list(x):
    if isinstance(x, dict):
        return list(set(x.values()))
    elif isinstance(x, basestring):
        return [x]
    else:
        return None

Autres conseils

type(dict()) dit « faire une nouvelle dict, puis savoir ce que son type est ». Il est plus rapide de dire que « dict ». Mais si vous voulez juste vérifier le type, d'une manière plus idiomatiques est isinstance(x, dict).

Notez que isinstance comprend également les 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

types intégrés en Python ont construit dans les noms:

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

Notez BTW est opérateur. Cependant, la vérification de type (si vous voulez l'appeler ainsi) est généralement fait en enroulant un test spécifique de type dans un essai, sauf clause, car il est pas tant le type de la variable qui est important, mais si vous pouvez faire un certain quelque chose avec elle ou non.

isinstance est preferrable sur le type, car il évalue également vrai lorsque vous comparez une instance d'objet avec ses superclasse, ce qui signifie essentiellement que vous ne jamais avoir à cas particulier votre ancien code pour l'utiliser avec dict ou sous-str.

Par exemple:

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

Bien sûr, il pourrait y avoir des situations où vous ne voudriez pas ce comportement, mais ce sont -hopefully- beaucoup moins fréquents que les cas où vous ne le voulez.

Je pense que je vais aller à l'approche de frappe de canard - « si ça marche comme un canard, il caquette comme un canard, son canard ». De cette façon, vous devez vous inquiétez pas si la chaîne est unicode ou ascii.

Voici ce que je ferai:

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 sont invités à commenter ce type d'utilisation de duck typing, je l'ai utilisé mais je me suis présenté au concept exact derrière elle ces derniers temps et je suis très excité à ce sujet. Je voudrais donc savoir si c'est un surpuissant à faire.

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

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, en fonction de votre code un ou l'autre est probablement considéré comme mieux que cela même. L'un est de ne pas regarder avant de sauter

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

L'autre approche est de Guido et est une forme de surcharge de fonction qui laisse votre code plus ouvert terminé.

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

Cela devrait fonctionner - donc non, il n'y a rien de mal avec votre code. Cependant, il pourrait également ê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 pythonique ne dites-vous?


Modifier .. conseils de Avisser Ne écoutant, le code fonctionne aussi comme ça, et semble plus agréable:

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

Vous pouvez consulter typecheck. http://pypi.python.org/pypi/typecheck

module de vérification de type pour Python

Ce paquet fournit de puissantes installations de contrôle de type temps d'exécution pour les fonctions Python, des méthodes et des générateurs. Sans exiger un préprocesseur personnalisé ou une modification de la langue, le paquet typecheck permet aux programmeurs et ingénieurs d'assurance qualité pour faire des affirmations précises sur l'entrée et la sortie de leur code.

Je l'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'utilisé ce lieu de isinstance, mais ...

*sigh*

Non, les arguments en python est contrôle de type pas nécessaire. Il est jamais nécessaire.

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

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

TypeChecking mal réutilisation du code et réduit les performances. Avoir une fonction effectue des choses différentes en fonction du type de l'objet est passé sujettes aux bugs et a un comportement plus difficile à comprendre et à maintenir.

Vous avez les options suivantes plus raisonnables:

1) Faire une unique_values fonction qui convertit dicts dans les listes de valeurs uniques:

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

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

myfunction([some_string])

Si vous devez passer un dict, vous faites:

myfunction(unique_values(some_dict))

C'est votre meilleure option, il est propre, facile à comprendre et à entretenir. N'importe qui la lecture du code comprend immediatelly ce qui se passe, et vous n'avez pas à typer.

2) Faire deux fonctions, l'une qui accepte des listes de chaînes et qui accepte dicts. Vous pouvez faire un appel l'autre interne, dans le plus pratique manière (myfunction_dict peut créer une liste de chaînes et d'appeler myfunction_list).

Dans tous les cas, ne typecheck pas . Il est tout à fait inutile et a seulement inconvénients. Factoriser votre code plutôt que d'une manière que vous ne avez pas besoin de typer. Vous obtenez seulement des avantages à le faire, à la fois à court et à long terme.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top