Question

Quel est le meilleur moyen de vérifier si un objet donné est d'un type donné? Que diriez-vous de vérifier si l'objet hérite d'un type donné?

Disons que j'ai un objet o . Comment puis-je vérifier s'il s'agit d'un str ?

Était-ce utile?

La solution

Pour vérifier si o est une instance de str ou de toute sous-classe de str , utilisez isinstance (ce serait la méthode" canonique "):

if isinstance(o, str):

Pour vérifier si le type de o est exactement str (sous-classes exclues):

if type(o) is str:

Ce qui suit fonctionne également et peut être utile dans certains cas:

if issubclass(type(o), str):

Voir Fonctions intégrées dans la référence de la bibliothèque Python pour obtenir des informations pertinentes.

Une dernière remarque: dans ce cas, si vous utilisez Python 2, vous souhaiterez peut-être utiliser:

if isinstance(o, basestring):

car cela interceptera également les chaînes Unicode ( unicode n'est pas une sous-classe de str ; str et unicode sont des sous-classes de chaîne de base ). Notez que basestring n'existe plus dans python 3, où il y a une séparation stricte des chaînes ( str ) et des données binaires ( octets ).

Sinon, isinstance accepte un tuple de classes. Cela retournera True si x est une instance d'une sous-classe de l'un des éléments suivants (str, unicode):

if isinstance(o, (str, unicode)):

Autres conseils

Le plus moyen Pythonic de vérifier le type d'un objet consiste à ... ne pas le vérifier.

Etant donné que Python encourage Duck Typing , il vous suffit de d'essayer ... sauf utiliser les méthodes de l'objet comme vous le souhaitez. Ainsi, si votre fonction recherche un objet fichier accessible en écriture, ne vérifiez pas qu'il s'agit d'une sous-classe du fichier , essayez simplement d'utiliser son .write () méthode!

Bien sûr, parfois, ces jolies abstractions tombent en panne et isinstance (obj, cls) est ce dont vous avez besoin. Mais utilisez avec parcimonie.

isinstance (o, str) renverra True si o est un str ou est d'un type qui hérite de str .

type (o) est str renverra True si et seulement si o est une str. Il renverra False si o est d'un type qui hérite de str .

Après avoir posé la question et y avoir répondu, des indications de type ont été ajoutées à Python . Les astuces de type en Python permettent de contrôler les types, mais d'une manière très différente des langages à typage statique. Les astuces de types en Python associent les types d'arguments attendus aux fonctions en tant que données accessibles à l'exécution associées aux fonctions, ce qui permet de contrôler les types . Exemple de syntaxe de type:

def foo(i: int):
    return i

foo(5)
foo('oops')

Dans ce cas, nous souhaitons qu'une erreur soit déclenchée pour foo ('oops') car le type annoté de l'argument est int . L'indicateur de type ajouté ne ne provoque pas une erreur lors de l'exécution normale du script. Cependant, il ajoute des attributs à la fonction décrivant les types attendus que d'autres programmes peuvent interroger et utiliser pour vérifier les erreurs de type.

L’un de ces autres programmes permettant de rechercher l’erreur de type est mypy :

mypy script.py
script.py:12: error: Argument 1 to "foo" has incompatible type "str"; expected "int"

(Vous devrez peut-être installer mypy à partir de votre gestionnaire de paquets. Je ne pense pas qu'il soit fourni avec CPython, mais semble avoir un certain niveau de "fonctionnalité".)

La vérification de type de cette manière diffère de la vérification de type dans les langages compilés statiquement typés. Les types étant dynamiques en Python, la vérification du type doit être effectuée au moment de l'exécution, ce qui impose un coût, même pour les programmes corrects, si nous insistons pour que cela se produise à chaque fois. Les vérifications de type explicites peuvent également être plus restrictives que nécessaire et provoquer des erreurs inutiles (par exemple, l’argument doit-il vraiment être de type list ou tout ce qui est itératif est-il suffisant?).

L'avantage de la vérification de type explicite est qu'elle peut détecter les erreurs plus tôt et donner des messages d'erreur plus clairs que la saisie simplifiée. Les exigences exactes d’un type de canard ne peuvent être exprimées que par une documentation externe (espérons que ce soit exhaustif et précis) et que des erreurs provenant de types incompatibles peuvent se produire loin de leur origine.

Les indications de type de Python sont conçues pour offrir un compromis dans lequel les types peuvent être spécifiés et vérifiés, sans aucun coût supplémentaire lors de l’exécution habituelle du code.

Le package typing propose des variables de type qui peuvent être utilisées dans les indicateurs de type pour exprimer les comportements nécessaires sans nécessiter de types particuliers. Par exemple, il inclut des variables telles que Iterable et Callable pour les astuces spécifiant la nécessité de tout type présentant ces comportements.

Alors que les astuces de type sont le moyen le plus pythonique de vérifier les types, il est souvent encore plus pythonique de ne pas vérifier les types du tout et de s’appuyer sur la frappe à la machine. Les indications de type sont relativement nouvelles et le jury n’a toujours pas choisi la solution la plus pythonique. Comparaison relativement peu controversée mais très générale: les astuces sur les types fournissent une forme de documentation qui peut être appliquée, qui permet au code de générer des erreurs plus tôt et plus facile à comprendre, qui peuvent intercepter des erreurs impossibles à saisir, et qui peuvent être vérifiées statiquement (de manière inhabituelle). sens mais cela reste en dehors du temps d’exécution). En revanche, le typage de canard est depuis longtemps une méthode pythonique, il n’impose pas la surcharge cognitive du typage statique, il est moins bavard et accepte tous les types viables, puis certains.

Voici un exemple pour lequel taper sur un canard est diabolique sans savoir quand il est dangereux. Par exemple: Voici le code Python (en omettant éventuellement l’indentation appropriée), notez que cette La situation est évitable en prenant soin des fonctions isinstance et issubassof afin de s’assurer que lorsque vous avez vraiment besoin d’un canard, vous n’obtenez pas de bombe.

class Bomb:
    def __init__(self):
        ""

    def talk(self):
        self.explode()

    def explode(self):
        print "BOOM!, The bomb explodes."

class Duck:
    def __init__(self):
        ""
    def talk(self):
        print "I am a duck, I will not blow up if you ask me to talk."    

class Kid:
    kids_duck = None

    def __init__(self):
        print "Kid comes around a corner and asks you for money so he could buy a duck."

    def takeDuck(self, duck):
        self.kids_duck = duck
        print "The kid accepts the duck, and happily skips along"

    def doYourThing(self):
        print "The kid tries to get the duck to talk"
        self.kids_duck.talk()

myKid = Kid()
myBomb = Bomb()
myKid.takeDuck(myBomb)
myKid.doYourThing()
isinstance(o, str)

Lien vers les documents

Je pense que l’utilisation intéressante d’un langage dynamique comme Python est que vous ne devriez vraiment pas avoir à vérifier quelque chose comme ça.

Je voudrais simplement appeler les méthodes requises sur votre objet et attraper un AttributeError . Ceci vous permettra plus tard d’appeler vos méthodes avec d’autres objets (apparemment non liés) pour accomplir différentes tâches, telles que le moquage d’un objet à des fins de test.

Je l'ai beaucoup utilisé pour obtenir des données sur le Web avec urllib2.urlopen () , qui renvoie un fichier tel que . Cela peut à son tour être passé à presque toutes les méthodes qui lisent un fichier, car elles implémentent la même méthode read () en tant que fichier réel.

Mais je suis sûr qu'il existe un moment et un lieu pour utiliser isinstance () , sinon ce ne serait probablement pas là:)

Pour Hugo:

Vous voulez probablement dire liste plutôt que tableau , mais cela pointe tout le problème de la vérification de type - vous ne voulez pas savoir si l'objet en question est un liste, vous voulez savoir s’il s’agit d’une séquence ou d’un objet unique. Essayez donc de l’utiliser comme une séquence.

Dites que vous souhaitez ajouter l'objet à une séquence existante ou, s'il s'agit d'une séquence d'objets, ajoutez-les tous

try:
   my_sequence.extend(o)
except TypeError:
  my_sequence.append(o)

Un truc avec ceci est que vous travaillez avec des chaînes et / ou des séquences de chaînes, ce qui est délicat, car une chaîne est souvent considérée comme un objet unique, mais c’est aussi une séquence de caractères. Pire que cela, car c'est vraiment une séquence de chaînes d'une seule longueur.

Je choisis généralement de concevoir mon API de manière à ce qu'elle n'accepte qu'une valeur ou une séquence - cela simplifie les choses. Il n'est pas difficile de mettre un [] autour de votre valeur unique lorsque vous le transmettez si nécessaire.

(Bien que cela puisse provoquer des erreurs avec les chaînes, elles ressemblent à des séquences.)

Pour les validations de types plus complexes, j'aime bien l'approche de typeguard pour la validation basée sur des annotations d'indices de type python. :

from typeguard import check_type
from typing import List

try:
    check_type('mylist', [1, 2], List[int])
except TypeError as e:
    print(e)

Vous pouvez effectuer des validations très complexes de manière très propre et lisible.

check_type('foo', [1, 3.14], List[Union[int, float]])
# vs
isinstance(foo, list) and all(isinstance(a, (int, float)) for a in foo) 

Vous pouvez vérifier avec la ligne ci-dessous quel type de caractère a la valeur donnée:

def chr_type(chrx):
    if chrx.isalpha()==True:
        return 'alpha'
    elif chrx.isdigit()==True:
        return 'numeric'
    else:
        return 'nothing'

chr_type("12)
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top