Question Déterminer le type d'un objet?


Existe-t-il un moyen simple de déterminer si une variable est une liste, un dictionnaire ou quelque chose d'autre? Je récupère un objet qui peut être de type et je dois être capable de faire la différence.


1378
2018-02-08 21:37


origine


Réponses:


Pour obtenir le type d'un objet, vous pouvez utiliser le built-in type() fonction. Passer un objet en tant que seul paramètre retournera l'objet type de cet objet:

>>> type([]) is list
True
>>> type({}) is dict
True
>>> type('') is str
True
>>> type(0) is int
True
>>> type({})
<type 'dict'>
>>> type([])
<type 'list'>

Cela fonctionne bien sûr aussi pour les types personnalisés:

>>> class Test1 (object):
        pass
>>> class Test2 (Test1):
        pass
>>> a = Test1()
>>> b = Test2()
>>> type(a) is Test1
True
>>> type(b) is Test2
True

Notez que type() ne retournera que le type immédiat de l'objet, mais ne pourra pas vous parler de l'héritage de type.

>>> type(b) is Test1
False

Pour couvrir cela, vous devez utiliser le isinstance fonction. Cela fonctionne bien sûr aussi pour les types intégrés:

>>> isinstance(b, Test1)
True
>>> isinstance(b, Test2)
True
>>> isinstance(a, Test1)
True
>>> isinstance(a, Test2)
False
>>> isinstance([], list)
True
>>> isinstance({}, dict)
True

isinstance() est généralement le moyen privilégié pour garantir le type d'un objet car il accepte également les types dérivés. Donc, sauf si vous avez réellement besoin de l'objet type (pour une raison quelconque), en utilisant isinstance() est préféré à type().

Le deuxième paramètre de isinstance() accepte également un tuple de types, il est donc possible de vérifier plusieurs types à la fois. isinstance retournera alors true si l'objet est de l'un de ces types:

>>> isinstance([], (tuple, list, set))
True

1603
2018-02-08 21:40



Vous pouvez le faire en utilisant type():

>>> a = []
>>> type(a)
<type 'list'>
>>> f = ()
>>> type(f)
<type 'tuple'>

141
2018-02-08 21:39



Il pourrait être plus Pythonic d'utiliser un try...except bloc. De cette façon, si vous avez une classe qui fait des charlatans comme une liste, ou des charlatans comme un dict, elle se comportera correctement quel que soit son type vraiment est.

Pour clarifier, la méthode préférée de "raconter la différence" entre les types de variables est avec quelque chose appelé typage de canard: tant que les méthodes (et les types de retour) auxquelles une variable répond sont celles attendues par votre sous-programme, traitez-la comme vous l'attendez. Par exemple, si vous avez une classe qui surcharge les opérateurs de support avec getattr et setattr, mais utilise un schéma interne amusant, il serait approprié qu'il se comporte comme un dictionnaire si c'est ce qu'il essaie d'imiter.

L'autre problème avec le type(A) is type(B) la vérification est que si A est une sous-classe de B, il évalue à false quand, par programme, vous espérez que ce serait true. Si un objet est une sous-classe d'une liste, cela devrait fonctionner comme une liste: vérifier le type tel que présenté dans l'autre réponse empêchera cela. (isinstance fonctionnera, cependant).


37
2018-02-08 21:43



Sur les instances d'objet vous avez aussi:

__class__

attribut. Voici un exemple tiré de la console Python 3.3

>>> str = "str"
>>> str.__class__
<class 'str'>
>>> i = 2
>>> i.__class__
<class 'int'>
>>> class Test():
...     pass
...
>>> a = Test()
>>> a.__class__
<class '__main__.Test'>

Attention, dans les classes python 3.x et New-Style (disponibles à partir de Python 2.6), la classe et le type ont été fusionnés, ce qui peut parfois conduire à des résultats inattendus. Principalement pour cette raison ma façon préférée de tester les types / classes est à la isinstance fonction intégrée.


30
2018-06-26 21:38



Déterminer le type d'un objet Python

Déterminer le type d'un objet avec type

>>> obj = object()
>>> type(obj)
<class 'object'>

Bien que cela fonctionne, évitez les attributs de soulignement doubles comme __class__ - ils ne sont pas sémantiquement publics, et, même si ce n'est peut-être pas le cas, les fonctions intégrées ont généralement un meilleur comportement.

>>> obj.__class__ # avoid this!
<class 'object'>

vérification de type

Existe-t-il un moyen simple de déterminer si une variable est une liste, un dictionnaire ou quelque chose d'autre? Je récupère un objet qui peut être de type et je dois être capable de faire la différence.

Eh bien, c'est une question différente, n'utilisez pas le type - utilisation isinstance:

def foo(obj):
    """given a string with items separated by spaces, 
    or a list or tuple, 
    do something sensible
    """
    if isinstance(obj, str):
        obj = str.split()
    return _foo_handles_only_lists_or_tuples(obj)

Cela couvre le cas où votre utilisateur pourrait faire quelque chose d'intelligent ou sensible en sous-classe str - selon le principe de la substitution Liskov, vous voulez pouvoir utiliser des instances de sous-classes sans casser votre code - et isinstance soutient cela.

Utiliser des abstractions

Encore mieux, vous pouvez rechercher une classe de base abstraite spécifique collections ou numbers:

from collections import Iterable
from numbers import Number

def bar(obj):
    """does something sensible with an iterable of numbers, 
    or just one number
    """
    if isinstance(obj, Number): # make it a 1-tuple
        obj = (obj,)
    if not isinstance(obj, Iterable):
        raise TypeError('obj must be either a number or iterable of numbers')
    return _bar_sensible_with_iterable(obj)

Ou simplement ne pas vérifier le type explicitement

Ou, peut-être le meilleur de tous, utilisez Duck-Typing, et ne tapez pas explicitement votre code. Duck-typing soutient Liskov Substitution avec plus d'élégance et moins de verbosité.

def baz(obj):
    """given an obj, a dict (or anything with an .items method) 
    do something sensible with each key-value pair
    """
    for key, value in obj.items():
        _baz_something_sensible(key, value)

Conclusion

  • Utilisation type pour obtenir réellement la classe d'une instance.
  • Utilisation isinstance vérifier explicitement les sous-classes réelles ou les abstractions enregistrées.
  • Et évitez simplement de vérifier le type là où c'est logique.

14
2018-03-14 21:12



Vous pouvez utiliser type() ou isinstance().

>>> type([]) is list
True

Soyez averti que vous pouvez clobber list ou tout autre type en affectant une variable dans la portée actuelle du même nom.

>>> the_d = {}
>>> t = lambda x: "aight" if type(x) is dict else "NOPE"
>>> t(the_d) 'aight'
>>> dict = "dude."
>>> t(the_d) 'NOPE'

Au-dessus nous voyons que dict est réaffecté à une chaîne, donc le test:

type({}) is dict

...échoue.

Pour contourner cela et utiliser type() plus prudemment:

>>> import __builtin__
>>> the_d = {}
>>> type({}) is dict
True
>>> dict =""
>>> type({}) is dict
False
>>> type({}) is __builtin__.dict
True

10
2018-05-31 21:57



Alors que les questions sont assez anciennes, j'ai trébuché là-dessus tout en trouvant moi-même une manière correcte, et je pense qu'il faut encore clarifier, au moins pour Python 2.x (n'a pas vérifié sur Python 3, mais comme le problème se pose avec les classes classiques qui ont disparu sur une telle version, cela n'a probablement pas d'importance).

Ici, j'essaie de répondre à la question du titre: comment puis-je déterminer le type d'un objet arbitraire? D'autres suggestions sur l'utilisation ou non d'isinstance sont très bien dans de nombreux commentaires et réponses, mais je ne réponds pas à ces préoccupations.

Le principal problème avec le type() approche est que cela ne fonctionne pas correctement avec les instances de style ancien:

class One:
    pass

class Two:
    pass


o = One()
t = Two()

o_type = type(o)
t_type = type(t)

print "Are o and t instances of the same class?", o_type is t_type

L'exécution de cet extrait produirait:

Are o and t instances of the same class? True

Ce qui, je le défends, n'est pas ce à quoi la plupart des gens s'attendraient.

le __class__ approche est la plus proche de la correction, mais cela ne fonctionnera pas dans un cas crucial: lorsque l'objet transmis est un ancien classe (pas une instance!), puisque ces objets n'ont pas cet attribut.

C'est le plus petit bout de code que je puisse penser qui réponde à une telle question légitime d'une manière cohérente:

#!/usr/bin/env python
from types import ClassType
#we adopt the null object pattern in the (unlikely) case
#that __class__ is None for some strange reason
_NO_CLASS=object()
def get_object_type(obj):
    obj_type = getattr(obj, "__class__", _NO_CLASS)
    if obj_type is not _NO_CLASS:
        return obj_type
    # AFAIK the only situation where this happens is an old-style class
    obj_type = type(obj)
    if obj_type is not ClassType:
        raise ValueError("Could not determine object '{}' type.".format(obj_type))
    return obj_type

4
2018-06-17 08:35



En aparté aux réponses précédentes, il convient de mentionner l'existence de collections.abc qui contient plusieurs classes de base abstraites (ABCs) qui complètent le typage du canard.

Par exemple, au lieu de vérifier explicitement si quelque chose est une liste avec:

isinstance(my_obj, list)

vous pourriez, si vous êtes seulement intéressé à voir si l'objet que vous avez permet d'obtenir des objets, utilisez collections.abc.Sequence:

from collections.abc import Sequence
isinstance(my_obj, Sequence) 

si vous êtes strictement intéressé par les objets qui permettent d'obtenir, le réglage et suppression d'éléments (par exemple mutable séquences), vous opteriez pour collections.abc.MutableSequence.

Beaucoup d'autres ABC sont définis ici, Mapping pour les objets qui peuvent être utilisés comme des cartes, Iterable, Callable, etc. Une liste complète de tous ceux-ci peut être vu dans la documentation pour collections.abc.


3
2017-12-07 15:50



soyez prudent en utilisant isinstance

isinstance(True, bool)
True
>>> isinstance(True, int)
True

mais tapez

type(True) == bool
True
>>> type(True) == int
False

2
2017-11-14 11:22