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

En utilisant isinstance():

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

933
2017-10-11 03:50


origine


Réponses:


Pour résumer le contenu d'autres réponses (déjà bonnes!), isinstance prend en charge l'héritage (une instance d'une classe dérivée est un exemple d'une classe de base), tout en vérifiant l'égalité des type ne le fait pas (il exige l'identité des types et rejette les instances de sous-types, sous-classes AKA).

Normalement, en Python, vous voulez que votre code prenne en charge l'héritage, bien sûr (puisque l'héritage est si pratique, il serait mauvais d'arrêter le code en utilisant le vôtre!), Donc isinstance est moins mauvais que la vérification de l'identité de types car il prend en charge l'héritage de façon transparente.

Ce n'est pas ça isinstance est bien, attention, c'est juste moins mauvais que de vérifier l'égalité des types. La solution normale, Pythonic, préférée est presque invariablement "dactylographie": essayez d'utiliser l'argument comme si il était d'un certain type désiré, le faire dans un try/except instruction attraper toutes les exceptions qui pourraient survenir si l'argument n'était pas en fait de ce type (ou tout autre type imitant bien le canard ;-), et dans le except clause, essayez autre chose (en utilisant l'argument "comme si" il était d'un autre type).

basestring  est, cependant, un cas assez particulier - un type intégré qui existe seulement pour vous permettre d'utiliser isinstance (tous les deux str et unicode sous-classe basestring). Les chaînes sont des séquences (vous pouvez les faire défiler, les indexer, les découper, ...), mais vous voulez généralement les traiter comme des types "scalaires" - c'est quelque peu inconcevable (mais un cas d'utilisation raisonnablement fréquent) pour traiter toutes sortes de les chaînes (et peut-être d'autres types scalaires, c'est-à-dire, celles que vous ne pouvez pas boucler) d'une manière, tous les conteneurs (listes, ensembles, dicts, ...) d'une autre manière, et basestring plus isinstance vous aide à faire cela - la structure générale de cet idiome est quelque chose comme:

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

Tu pourrais dire ça basestring est un 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, a été accepté et a été implémenté à partir de Python 2.6 et 3.0.

Le PEP indique clairement que, bien que l'ABC puisse souvent remplacer le typage du canard, il n'y a généralement pas de grande pression pour le faire (voir ici). Les ABCs implémentés dans les versions récentes de Python offrent cependant des bonus supplémentaires: isinstance (et issubclass) peut maintenant signifier plus que simplement "[une instance de] une classe dérivée" (en particulier, n'importe quelle classe peut être "enregistrée" avec un ABC pour qu'elle apparaisse comme une sous-classe, et ses instances comme instances de l'ABC); et 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 modèle (voir ici et ici [[partie II]] pour plus sur le DP TM, en général et spécifiquement en Python, indépendant de ABC).

Pour la mécanique sous-jacente de la prise en charge d'ABC, telle qu'elle est proposée dans Python 2.6, voir ici; pour leur version 3.1, très similaire, voir ici. Dans les deux versions, module de bibliothèque standard des collections (c'est la version 3.1 - pour la version 2.6 très similaire, voir ici) offre plusieurs ABC utiles.

Dans le but de cette réponse, la chose clé à retenir à propos de ABC (au-delà d'un placement sans doute plus naturel pour la fonctionnalité TM DP, par rapport à l'alternative classique Python de classes mixin telles que UserDict.DictMixin) est qu'ils font isinstance (et issubclass) beaucoup plus attrayant et omniprésent (en Python 2.6 et en avant) qu'auparavant (en 2.5 et avant), et par conséquent, faire de l'égalité des types de vérification une pratique encore pire dans les versions récentes de Python qu'elle ne l'était .


988
2017-10-11 04:31



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 est vrai pour les sous-classes, aussi.

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


260
2017-10-11 03:58



Différences entre isinstance() et type() en 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, is 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 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() en 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 faire passer un dict qui est une sous-classe de dict (comme nous devrions pouvoir, si nous attendons notre code à suivre le principe de Liskov Substitution, que les sous-types peuvent être substitués aux types) notre code se brise!

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')]))

résultats 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 la Mappingprotocole, 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 ce type peut être utilisé pour vérifier 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, sauf si vous autorisez uniquement ces types:

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

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

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

Conclusion

Donc, puisque nous voulons soutenir les sous-classes de substitution, dans la plupart des cas, nous voulons éviter la vérification de type avec type et préfèrent vérifier avec isinstance - sauf si vous avez vraiment besoin de connaître la classe précise d'une instance.


60
2018-02-06 04:13



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

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

ou, en utilisant le basestring classe abstraite:

if isinstance(b, basestring):
    do_something_else()

55
2017-10-11 03:54



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 aussi des noms pour   types correspondants.

Alors isinstance() devrait être préféré à type().


11
2017-10-11 03:59



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

Cependant, nous pouvons obtenir le même abc .__ instancecheck__ selon __instancecheck__.

D'en haut abc.__instancecheck__, après avoir utilisé le test 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

Je reçois cette conclusion, Pour 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 vaut ne pas mélanger l'utilisation relative and absolutely import, utilisation absolutely import de project_dir (ajouté par sys.path)


0
2018-05-10 08:00