type - python typing enum




Quelles sont les différences entre type() et isinstance()? (4)

Différences entre isinstance() et type() dans Python?

Vérification de type avec

isinstance(obj, Base)

permet des instances de sous-classes et plusieurs bases possibles:

isinstance(obj, (Base1, Base2))

alors que la vérification de type avec

type(obj) is Base

prend uniquement en charge le type référencé.

En tant que sidenote, est probablement plus approprié que

type(obj) == Base

parce que les classes sont des singletons.

Eviter la vérification de type - utiliser Polymorphisme (dactylographie)

En Python, vous voulez généralement autoriser n'importe quel type pour vos arguments, le traiter comme prévu, et si l'objet ne se comporte pas comme prévu, il déclenchera une erreur appropriée. C'est ce qu'on appelle le polymorphisme, également connu sous le nom de dactylographie.

def function_of_duck(duck):
    duck.quack()
    duck.swim()

Si le code ci-dessus fonctionne, on peut supposer que notre argument est un canard. Ainsi, nous pouvons passer à d'autres choses sont des sous-types réels de canard:

function_of_duck(mallard)

ou ça marche 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 sensées à faire avec différents types d'objets. Par exemple, l'objet Pandas Dataframe peut être construit à partir de dicts ou d' enregistrements. Dans un tel cas, votre code doit savoir quel type d'argument il obtient afin qu'il puisse le gérer correctement.

Donc, pour répondre à la question:

Différences entre isinstance() et type() dans Python?

Permettez-moi de démontrer la différence:

type

Supposons que vous ayez besoin d'un certain comportement si votre fonction obtient un certain type d'argument (un cas d'utilisation courant pour les constructeurs). Si vous vérifiez pour le type comme ceci:

def foo(data):
    '''accepts a dict to construct something, string support in future'''
    if type(data) is dict:
        # we're only going to test for dicts for now
        raise ValueError('only dicts are supported for now')

Si nous essayons de transmettre un dict qui est une sous-classe de dict (comme nous devrions pouvoir, si nous attendons que notre code suive le principe de la substitution de Liskov , que les sous-types puissent être substitués aux types) nos codes break!

from collections import OrderedDict

foo(OrderedDict([('foo', 'bar'), ('fizz', 'buzz')]))

déclenche 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 différents types. Dans notre cas, si nous attendons seulement le protocole 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

Conclusion

Donc, comme nous voulons prendre en charge les sous-classes substituantes, dans la plupart des cas, nous voulons éviter la vérification de type avec type et préférer la vérification de type avec isinstance , sauf si vous avez vraiment besoin de connaître la classe précise d'une instance.

Quelles sont les différences entre ces deux fragments de code? En utilisant type() :

import types

if type(a) is types.DictType:
    do_something()
if type(b) in types.StringTypes:
    do_something_else()

En utilisant isinstance() :

if isinstance(a, dict):
    do_something()
if isinstance(b, str) or isinstance(b, unicode):
    do_something_else()

Ce dernier est préféré, car il traitera correctement les sous-classes. En fait, votre exemple peut être écrit encore plus facilement parce isinstance() le deuxième paramètre de isinstance() peut être un tuple:

if isinstance(b, (str, unicode)):
    do_something_else()

ou, en utilisant la classe abstraite basestring :

if isinstance(b, basestring):
    do_something_else()


Voici pourquoi isinstance vaut mieux que type :

class Vehicle:
    pass

class Truck(Vehicle):
    pass

dans ce cas, un objet de camion est un véhicule, mais vous obtiendrez ceci:

isinstance(Vehicle(), Vehicle)  # returns True
type(Vehicle()) == Vehicle      # returns True
isinstance(Truck(), Vehicle)    # returns True
type(Truck()) == Vehicle        # returns False, and this probably won't be what you want.

En d'autres termes, isinstance est également vrai pour les sous-classes.

Voir aussi: Comment comparer le type d'un objet en Python?





types