web-dev-qa-db-fra.com

Comment définir une condition en python en fonction des types de données?

Cette question semble simple, mais je n'arrive pas à la comprendre. Je sais que vous pouvez vérifier les types de données en python, mais comment définir une condition en fonction du type de données? Par exemple, si je dois écrire un code qui trie dans un dictionnaire/une liste et additionne tous les entiers, comment puis-je isoler la recherche pour ne rechercher que des entiers?

Je suppose qu'un exemple rapide ressemblerait à quelque chose comme ceci:

y = []
for x in somelist:
    if type(x) == <type 'int'>:  ### <--- psuedo-code line
    y.append(x)
print sum(int(z) for z in y)

Donc, pour la ligne 3, comment pourrais-je définir une telle condition?

12
01110100

Que diriez-vous,

if isinstance(x, int):

mais une manière plus propre serait tout simplement

sum(z for z in y if isinstance(z, int))
32
Jakob Bowyer

Il y a un très gros "ça dépend" de la vérification de type en Python. Il existe de nombreuses façons de traiter les types, et tous ont leurs avantages et leurs inconvénients. Avec Python3, plusieurs autres ont émergé.

  • Égalité de type explicite

Les types sont des objets de première classe et vous pouvez les traiter comme n'importe quelle autre valeur. Donc, si vous voulez que le type de quelque chose soit égal à int, testez-le:

if type(x) == int:

C'est le type de test le plus restrictif: il nécessite l'égalité de type exacte. Souvent, ce n'est pas ce que vous voulez:

  • Elle exclut les types de substitution: une float ne serait pas valide, même si elle se comportait comme un int à plusieurs fins.
  • Elle exclut les sous-classes et les types abstraits: une jolie sous-classe int ou enum serait rejetée, même si elles sont logiquement des entiers.
    • Cela limite considérablement la portabilité: les chaînes Python2 peuvent être soitstr ou unicode, et les entiers peuvent être (soit)int ou long.

Notez que l'égalité de type explicite a est utilisée pour les opérations de bas niveau:

  • Certains types ne peuvent pas être sous-classés, tels que slice. Une vérification explicite est bien plus explicite ici.
  • Certaines opérations de bas niveau, telles que la sérialisation ou les C-API, nécessitent des types spécifiques.

Variantes

Une comparaison peut également être effectuée avec l'attribut __class__:

if x.__class__ == int:

Remarque Si une classe définit une propriété __class__, ce n'est pas la même chose que type(x).

Lorsque plusieurs classes doivent être vérifiées, l'utilisation d'une dict pour répartir les actions est plus extensible et peut être plus rapide (types ≥5-10) que les vérifications explicites. Ceci est particulièrement utile pour les conversions et la sérialisation:

dispatch_dict = {float: round, str: int, int: lambda x: x}
def convert(x):
    converter = self.dispatch_dict[type(x)]  # lookup callable based on type
    return converter(x)
  • Vérification d'instance sur les types explicites

Le test de type idiomatique utilise la variable isinstancebuiltin :

if isinstance(x, int):

Cette vérification est à la fois exacte et performante. C'est le plus souvent ce que les gens veulent pour vérifier les types:

  • Il gère correctement les sous-types. Une jolie sous-classe int passerait quand même ce test.
  • Il permet de vérifier plusieurs types à la fois. En Python2, exécuter isinstance(x, (int, long)) vous donne tous les entiers intégrés.

Plus important encore, les inconvénients sont la plupart du temps négligeables:

  • Il accepte toujours les sous-classes géniales qui se comportent de manière étrange. Etant donné que (n'importe quoi} _ peut être amené à se comporter de manière étrange, il est inutile de se protéger.
  • Cela peut facilement être aussi restrictif: de nombreuses personnes recherchent isinstance(x, list) lorsqu'une séquence (par exemple, Tuple) ou même un caractère itérable (par exemple, un generator) conviendrait également. Cela concerne davantage les bibliothèques à usage général que les scripts ou les applications.

Variantes

Si vous avez déjà un type, issubclass se comporte de la même manière:

if issubclass(x_type, int):
  • Vérification d'instance sur un type abstrait

Python a un concept de classes de base abstraites . En gros, ils expriment le sens des types, pas leur hiérarchie:

if isinstance(x, numbers.Real):  # accept anything you can sum up like a number

En d'autres termes, le type (x) ne fait pas nécessairement hériter de numbers.Real mais doit se comporter comme ce dernier. C'est quand même un concept très complexe et difficile:

  • Il est souvent excessif si vous recherchez des types de base. Un entier est simplement une int la plupart du temps.
  • Les personnes venant d’autres langues confondent souvent ses concepts.
    • Distinguer de par exemple C++, l'emphase est base abstraite classe par opposition à la classe abstraite base.
    • Les ABC peuvent être utilisés comme des interfaces Java, mais peuvent toujours avoir des fonctionnalités concrètes.

Cependant, il est incroyablement utile pour les bibliothèques génériques et les abstractions.

  • De nombreuses fonctions/algorithmes n'ont pas besoin de types explicites, mais simplement de leur comportement.
    • Si vous avez juste besoin de rechercher des éléments par clé, dict vous limite à un type spécifique en mémoire. En revanche, collections.abc.Mapping inclut également les wrappers de base de données, les grands dictionnaires sauvegardés sur disque, les conteneurs lazy, ... - et dict.
  • Il permet d’exprimer des contraintes de type partielles.
    • Il n'y a pas de type de base strict implémentant l'itération. Mais si vous comparez les objets à collections.abc.Iterable, ils fonctionnent tous dans une boucle for.
  • Il permet de créer des implémentations optimisées distinctes qui apparaissent sous le même type abstrait.

Bien que cela ne soit généralement pas nécessaire pour les scripts à jeter, je vous recommande fortement de l'utiliser pour tout ce qui vit au-delà de quelques versions de Python.

  • Conversion provisoire

La manière idiomatique de traiter les types n’est pas de les tester, mais de supposer qu’ils sont compatibles. Si vous attendez déjà des types incorrects dans votre entrée, ignorez tout ce qui n'est pas compatible:

try:
    ix = int(x)
except (ValueError, TypeError):
    continue  # not compatible with int, try the next one
else:
    a.append(ix)

Ce n'est pas réellement une vérification de type, mais sert généralement la même intention.

  • Il garantit vous avez le type attendu dans votre sortie.
  • Il dispose d'une marge de manœuvre limitée pour convertir les types incorrects, par exemple. spécialisation float à int.
  • Cela fonctionne sans que vous sachiez quels types sont conformes à int.

L'inconvénient majeur est qu'il s'agit d'une transformation explicite.

  • Vous pouvez accepter en silence les "mauvaises" valeurs, par exemple. convertir une str contenant un littéral.
  • Il convertit inutilement même les types qui seraient assez bons, par exemple. float à int quand vous avez juste besoin de chiffres.

La conversion est un outil efficace pour certains cas d'utilisation spécifiques. Cela fonctionne mieux si vous savez approximativement quelle est votre contribution et si vous devez donner des garanties quant à votre production.

  • Contrôle de l'entrée

La meilleure chose à faire est de vous assurer que vous n'avez jamais à vérifier le type en premier lieu. C'est un peu une méta-sujet, car cela dépend fortement du cas d'utilisation.

Ici, la source de somelist n'aurait jamais dû y mettre des non-nombres.

8
MisterMiyagi

permettez-moi de déclarer la variable x de type int

x = 2
if type(x) == type(1) or isinstance(x, int):  
    # do something

Les deux fonctionnent bien.

0
Naga Sreyas