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

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()

utilisant isinstance() :

if isinstance(a, dict):
    do_something()
if isinstance(b, str) or isinstance(b, unicode):
    do_something_else()
968
demandé sur TylerH 2009-10-11 07:50:54

6 réponses

Pour résumer le contenu d'autres (déjà bien!) réponses, isinstance s'adresse à l'héritage (une instance d'une classe dérivée est une instance d'une classe de base, aussi), alors que la vérification de l'égalité de type ne le fait pas (il exige l'identité des types et rejette les instances de sous-types, alias sous-classes).

normalement, en Python, vous voulez que votre code supporte l'héritage, bien sûr (puisque l'héritage est si pratique, il serait mauvais pour empêcher le code d'utiliser le vôtre de l'utiliser!), ainsi isinstance est moins mauvais que le contrôle d'identité de type s parce qu'il soutient parfaitement l'héritage.

ce n'est pas que isinstance est bon , pensez-vous-c'est juste moins mauvais que la vérification de l'égalité des types. La solution normale, pythonique, préférée est presque invariablement "duck typing": essayez d'utiliser l'argument comme si il était d'un certain type désiré, le faire dans un try / except déclaration attraper toutes les exceptions qui pourraient se poser si l'argument n'était pas en fait de ce type (ou tout autre type joliment canard imitant; -), et dans la clause except , essayer quelque chose d'autre (en utilisant l'argument "comme si" il était d'un autre type).

basestring est , cependant, tout à fait un cas spécial-un type de bâtiment qui existe seulement pour vous permettre d'utiliser isinstance (à la fois str et unicode sous-classe basestring ). Les chaînes sont des séquences (on peut les indexer, les couper en boucle, etc.)...), mais vous voulez généralement les traiter comme des types" scalaires " -il est quelque peu incovenient (mais un cas d'utilisation assez fréquente) pour traiter toutes sortes de chaînes (et peut-être d'autres types scalaires, c.-à-d., ceux que vous ne pouvez pas boucler sur) une voie, tous les conteneurs (listes, ensembles, dicts, ...) d'une autre manière, et basestring plus isinstance vous aide à le faire-la structure globale de cet idiome est quelque chose comme:

if isinstance(x, basestring)
  return treatasscalar(x)
try:
  return treatasiter(iter(x))
except TypeError:
  return treatasscalar(x)

on pourrait dire que basestring est une classe de Base abstraite ("ABC")-il n'offre aucune fonctionnalité concrète aux sous-classes, mais existe plutôt comme un" marqueur", principalement pour une utilisation avec isinstance . Le concept est évidemment en croissance en Python, depuis PEP 3119 , qui introduit une généralisation de celui-ci, a été accepté et a été mis en œuvre à partir de Python 2.6 et 3.0.

le PEP indique clairement que, bien que L'ABC puisse souvent remplacer le canard dactylographié, il n'y a généralement pas de grande pression pour le faire (voir ici ). Abc tel que mis en œuvre dans les dernières versions de Python n'offrent cependant des goodies supplémentaires: isinstance (et issubclass ) peut maintenant signifie plus que "[l'instance] une classe dérivée" (en particulier, toute classe peut être "enregistré" avec un ABC de sorte qu'il s'affiche comme une sous-classe, et ses instances les instances de L'ABC); et L'ABCs peut également offrir une commodité supplémentaire aux sous-classes réelles d'une manière très naturelle via des applications de modèle de conception de méthode de Template (voir ici et ici [[partie II]] pour plus de détails sur le DP TM, en général et spécifiquement en Python, indépendant de L'ABCs).

pour la mécanique sous-jacente du support ABC tel qu'offert en python 2.6, voir ici ; pour leur version 3.1, très similaire, voir ici . Dans les deux versions, le module de bibliothèque standard collections (c'est la version 3.1-Pour la version 2.6 très similaire, voir ici ) offre plusieurs ABC utiles.

pour les besoins de cette réponse, la chose clé à retenir à propos de L'ABC (au-delà d'un placement sans doute plus naturel pour la fonctionnalité TM DP, par rapport à L'alternative classique de python des classes de mixin telles que UserDict.DictMixin ) est qu'ils rendent isinstance (et issubclass ) beaucoup plus attrayant et envahissant (en python 2.6 et aller de l'avant) qu'ils ne l'étaient (en 2.5 et avant), et donc, par contraste, faire vérifier l'égalité de type une pratique encore pire dans les versions récentes de Python qu'il ne l'était déjà.

1034
répondu Alex Martelli 2017-12-18 20:30:05

Voici pourquoi isinstance est 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 vaut également pour les sous-classes.

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

273
répondu Peter 2017-05-23 12:18:24

Différences entre les isinstance() et type() en Python?

contrôle de Type avec

isinstance(obj, Base)

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

isinstance(obj, (Base1, Base2))

alors que le contrôle de type porte sur

type(obj) is Base

supporte uniquement le type référencé.


comme sidenote, is est probablement plus approprié que

type(obj) == Base

parce que les classes sont des Singleton.

Eviter la vérification de type-use polymorphisme (duck-typing)

en Python, habituellement vous voulez 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 soulèvera une erreur appropriée. Ceci est connu comme le polymorphisme, aussi connu comme duck-typing.

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

Si le code ci-dessus fonctionne, nous pouvons présumer notre argument est un canard. Ainsi nous pouvons passer dans d'autres choses 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.

toutefois, dans certains cas, il est souhaitable de procéder à un contrôle de type explicite. 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 . Dans un tel cas, votre code doit savoir quel type d'argument c'est l'obtention de sorte qu'il peut gérer correctement.

donc, pour répondre à la question:

différences entre isinstance() et type() en Python?

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

type

dites que vous devez vous assurer un certain comportement si votre fonction est un certain genre d'argument (un cas d'utilisation 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 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, si nous nous attendons à ce que notre code suive le principe de Liskov Substitution , que les sous-types peuvent être substitués pour les types) notre code 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 Liskov Substitution!:

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 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

réponse au commentaire:

il convient de noter que le type peut être utilisé pour vérifier la compatibilité avec plusieurs classes en utilisant 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, à moins que vous n'autorisiez spécifiquement que ces types:

isinstance(obj, (A, B, C))

la différence, encore une fois, est que isinstance supporte des sous-classes qui peuvent être substituées au parent sans briser le programme, une propriété connue sous le nom de substitution de Liskov.

encore mieux, cependant, inversez vos dépendances et ne Vérifiez pas du tout les types spécifiques.

Conclusion

donc, puisque nous voulons soutenir des sous-classes de substitution, dans la plupart des cas, nous voulons éviter vérification de type avec type et préférez vérification de type avec isinstance -à moins que vous ayez vraiment besoin de connaître la classe précise d'une instance.

64
répondu Aaron Hall 2018-08-26 12:47:58

cette dernière solution est préférable, car elle permet de traiter correctement les sous-classes. En fait, votre exemple peut être écrit encore plus facilement parce que le second paramètre de isinstance() peut être un tuple:

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

ou, à l'aide de la basestring classe abstraite:

if isinstance(b, basestring):
    do_something_else()
57
répondu John Millikin 2013-10-28 15:51:16

selon la documentation de python voici une déclaration:

8.15. types-noms pour les types intégrés

à partir de Python 2.2, intégré fonctions d'usine telles que int() et str() sont également des noms pour le types correspondants.

Donc isinstance() doit être préféré à type() .

11
répondu Xinus 2013-09-24 17:52:55

pour les différences réelles, nous pouvons le trouver dans code , mais je ne peux pas trouver l'implémentation du comportement par défaut du isinstance() .

Toutefois, nous pouvons obtenir un semblable abc.__instancecheck__ selon __instancecheck__ .

au-dessus de abc.__instancecheck__ , après avoir utilisé l'essai ci-dessous:

# file tree
# /test/__init__.py
# /test/aaa/__init__.py
# /test/aaa/aa.py
class b():
pass

# /test/aaa/a.py
import sys
sys.path.append('/test')

from aaa.aa import b
from aa import b as c

d = b()

print(b, c, d.__class__)
for i in [b, c, object]:
    print(i, '__subclasses__',  i.__subclasses__())
    print(i, '__mro__', i.__mro__)
    print(i, '__subclasshook__', i.__subclasshook__(d.__class__))
    print(i, '__subclasshook__', i.__subclasshook__(type(d)))
print(isinstance(d, b))
print(isinstance(d, c))

<class 'aaa.aa.b'> <class 'aa.b'> <class 'aaa.aa.b'>
<class 'aaa.aa.b'> __subclasses__ []
<class 'aaa.aa.b'> __mro__ (<class 'aaa.aa.b'>, <class 'object'>)
<class 'aaa.aa.b'> __subclasshook__ NotImplemented
<class 'aaa.aa.b'> __subclasshook__ NotImplemented
<class 'aa.b'> __subclasses__ []
<class 'aa.b'> __mro__ (<class 'aa.b'>, <class 'object'>)
<class 'aa.b'> __subclasshook__ NotImplemented
<class 'aa.b'> __subclasshook__ NotImplemented
<class 'object'> __subclasses__ [..., <class 'aaa.aa.b'>, <class 'aa.b'>]
<class 'object'> __mro__ (<class 'object'>,)
<class 'object'> __subclasshook__ NotImplemented
<class 'object'> __subclasshook__ NotImplemented
True
False

j'obtiens cette conclusion, Au lieu de type :

# according to `abc.__instancecheck__`, they are maybe different! I have not found negative one 
type(INSTANCE) ~= INSTANCE.__class__
type(CLASS) ~= CLASS.__class__

pour isinstance :

# guess from `abc.__instancecheck__`
return any(c in cls.__mro__ or c in cls.__subclasses__ or cls.__subclasshook__(c) for c in {INSTANCE.__class__, type(INSTANCE)})

BTW: mieux de ne pas mélanger les utiliser relative and absolutely import , utilisez absolutely import de project_dir( ajouté par sys.path )

0
répondu Cheney 2018-05-10 08:00:00