Différences entre isinstance()
et type()
en Python ?
Vérification de type avec
isinstance(obj, Base)
permet des instances de sous-classes et de multiples bases possibles :
isinstance(obj, (Base1, Base2))
alors que le contrôle de type avec
type(obj) is Base
ne prend en charge que le type référencé.
En guise d'aparté, is
est probablement plus approprié que
type(obj) == Base
parce que les classes sont des singletons.
Éviter la vérification de type - utiliser le polymorphisme (duck-typing)
En Python, vous voulez généralement autoriser n'importe quel type pour vos arguments, les traiter comme prévu, et si l'objet ne se comporte pas comme prévu, une erreur appropriée sera levée. C'est ce qu'on appelle le polymorphisme, également connu sous le nom de duck-typing.
def function_of_duck(duck):
duck.quack()
duck.swim()
Si le code ci-dessus fonctionne, nous pouvons supposer que notre argument est un canard. Ainsi, nous pouvons passer d'autres choses qui sont des sous-types réels de canard :
function_of_duck(mallard)
ou qui travaillent comme un canard :
function_of_duck(object_that_quacks_and_swims_like_a_duck)
et notre code fonctionne toujours.
Cependant, il y a des cas où il est souhaitable de vérifier explicitement le type. Peut-être avez-vous des choses sensibles à faire avec différents types d'objets. Par exemple, l'objet Dataframe de Pandas peut être construit à partir de dicts ou les dossiers. Dans un tel cas, votre code doit savoir quel type d'argument il reçoit afin de pouvoir le traiter correctement.
Donc, pour répondre à la question :
Différences entre isinstance()
et type()
en Python ?
Permettez-moi de vous démontrer la différence :
type
Disons que vous devez garantir un certain comportement si votre fonction reçoit un certain type d'argument (un cas d'utilisation courant pour les constructeurs). Si vous vérifiez le type comme ceci :
def foo(data):
'''accepts a dict to construct something, string support in future'''
if type(data) is not dict:
# we're only going to test for dicts for now
raise ValueError('only dicts are supported for now')
Si nous essayons de passer dans un dict qui est une sous-classe de dict
(comme nous devrions pouvoir le faire, si nous attendons de notre code qu'il respecte le principe du Substitution de Liskov , que les sous-types peuvent être substitués aux types) notre code se casse !
from collections import OrderedDict
foo(OrderedDict([('foo', 'bar'), ('fizz', 'buzz')]))
soulève une erreur !
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in foo
ValueError: argument must be a dict
isinstance
Mais si nous utilisons isinstance
nous pouvons soutenir la substitution de Liskov !
def foo(a_dict):
if not isinstance(a_dict, dict):
raise ValueError('argument must be a dict')
return a_dict
foo(OrderedDict([('foo', 'bar'), ('fizz', 'buzz')]))
renvoie à OrderedDict([('foo', 'bar'), ('fizz', 'buzz')])
Classes de base abstraites
En fait, nous pouvons faire encore mieux. collections
fournit des classes de base abstraites qui appliquent des protocoles minimaux pour divers types. Dans notre cas, si nous attendons seulement le Mapping
nous pouvons faire ce qui suit, et notre code devient encore plus flexible :
from collections import Mapping
def foo(a_dict):
if not isinstance(a_dict, Mapping):
raise ValueError('argument must be a dict')
return a_dict
Réponse au commentaire :
Il convient de noter que le type peut être utilisé pour vérifier plusieurs classes à l'aide de la fonction type(obj) in (A, B, C)
Oui, vous pouvez tester l'égalité des types, mais au lieu de ce qui précède, utilisez les bases multiples pour le flux de contrôle, sauf si vous n'autorisez spécifiquement que ces types :
isinstance(obj, (A, B, C))
La différence, encore une fois, est que isinstance
prend en charge les sous-classes qui peuvent être substituées au parent sans interrompre le programme, une propriété connue sous le nom de substitution Liskov.
Mieux encore, inversez vos dépendances et ne vérifiez pas du tout les types spécifiques.
Conclusion
Donc, puisque nous voulons supporter la substitution de sous-classes, dans la plupart des cas, nous voulons éviter la vérification de type avec type
et préfèrent le contrôle de type avec isinstance
- sauf si vous avez vraiment besoin de connaître la classe précise d'une instance.
2 votes
Note : Si ce n'est pas
str
etunicode
(où vous pouvez simplement vérifierbasestring
), vous pouvez utiliser un tuple pour vérifier plusieurs types. Pour vérifier sisomething
estint
oustr
utiliserisinstance(something, (int, str))
.1 votes
type()
retourne le type de l'objet que vous avez mis en argument, et n'est généralement pas utile à moins d'être comparé à un type réel (tel quetype(9) == int
).isinstance()
renvoie un booléen - vrai ou faux - selon que l'objet est du type donné.isinstance
est généralement plus élégant à utiliser plutôt que d'écrire une vérification d'égalité encombrante, dans la plupart des cas.