Определить тип объекта?

есть ли простой способ определить, является ли переменная списком, словарем или чем-то еще? Я возвращаю объект, который может быть любого типа, и мне нужно уметь отличать.

9 ответов


чтобы получить тип объекта, вы можете использовать встроенный type()


Вы можете сделать это с помощью type():

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

это может быть более подходящие для Python, чтобы использовать try...except блок. Таким образом, если у вас есть класс, который крякает, как список, или крякает, как дикт, он будет вести себя правильно независимо от того, какой его тип действительно есть.

чтобы уточнить, предпочтительный метод "определения разницы" между типами переменных-это то, что называется утиной типизацией: пока методы (и возвращаемые типы), на которые реагирует переменная, - это то, что ожидает ваша подпрограмма, относитесь к этому так, как вы ожидаете. Например, если у вас есть класс, который перегружает операторы кронштейн с getattr и setattr, но использует какую-то забавную внутреннюю схему, было бы целесообразно вести себя как словарь, если это то, что он пытается эмулировать.

другая проблема, с type(A) is type(B) проверка-это если A является наследником B, он оценивает в false когда, программно, вы надеетесь, что это будет true. Если объект является подклассом список, он должен работать как список: проверка типа, представленного в другом ответе, предотвратит это. (isinstance будет работать, однако).


на экземплярах объекта у вас также есть:

__class__
. Вот пример, взятый из консоли 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'>

остерегайтесь этого в python 3.x и в классах нового стиля (доступных дополнительно из Python 2.6) класс и тип были объединены, и это может когда-нибудь привести к неожиданным результатам. В основном по этой причине мой любимый способ тестирования типов/классов в isinstance встроенная функция.


Определите тип объекта Python

Определите тип объекта с помощью type

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

хотя он работает, избегайте двойных атрибутов подчеркивания, таких как __class__ - они не являются семантически публичными, и, хотя, возможно, не в этом случае, встроенные функции обычно имеют лучшее поведение.

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

тип проверки

есть ли простой способ определить, является ли переменная списком, словарем или чем-то еще еще? Я возвращаю объект, который может быть любого типа, и мне нужно уметь отличать.

Ну, это другой вопрос, не используйте type - use 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)

это охватывает случай, когда пользователь может делать что-то умное или дельное на подклассы str - согласно принципу подстановки Лискова, вы хотите иметь возможность использовать экземпляры подкласса, не нарушая свой код-и isinstance поддерживает это.

Использовать Абстракции

еще лучше, вы можете искать конкретный абстрактный базовый класс из collections или 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)

или просто не явно введите-check

или, возможно, лучше всего, использовать duck-typing и явно не вводить-проверьте свой код. Duck-typing поддерживает замену Liskov с большей элегантностью и меньшей многословностью.

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)

вывод

  • использовать type фактически получить класс экземпляра.
  • использовать isinstance чтобы явно проверить наличие фактических подклассов или зарегистрированных абстракций.
  • и просто избежать проверки типа, где это имеет смысл.

можно использовать type() или isinstance().

>>> type([]) is list
True

будьте предупреждены, что вы можете clobber list или любой другой тип, назначив переменную в текущей области с тем же именем.

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

выше мы видим, что dict получил назначение в строку, поэтому тест:

type({}) is dict

...неудачи.

обойти это и использовать type() более осторожно:

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

в то время как вопросы довольно старые, я наткнулся на это, выясняя правильный путь сам, и я думаю, что он все еще нуждается в уточнении,по крайней мере для Python 2.x (Не проверял Python 3, но поскольку проблема возникает с классическими классами, которые ушли в такой версии, это, вероятно, не имеет значения).

здесь я пытаюсь ответить на вопрос заголовка:как я могу определить тип произвольного объекта? Другие предложения об использовании или нет использование isinstance прекрасно во многих комментариях и ответах, но я не рассматриваю эти проблемы.

главная проблема type() подход заключается в том, что он не работает со старыми экземплярами:

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

выполнение этого фрагмента даст:

Are o and t instances of the same class? True

что я утверждаю, не то, что большинство людей было бы ожидать.

на __class__ подход наиболее близок к правильности, но он не будет работать в одном решающем случае: когда объект passed - in-это старый стиль класс (не экземпляр!), поскольку эти объекты не имеют такого атрибута.

Это самый маленький фрагмент кода, который я мог придумать, который удовлетворяет такому законному вопросу последовательным образом:

#!/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

в стороне от предыдущих ответов, стоит упомянуть о существовании collections.abc который содержит несколько абстрактных базовых классов (ABCs), которые дополняют типирование утки.

например, вместо явной проверки, является ли что-то списком с:

isinstance(my_obj, list)

вы могли бы, если вы заинтересованы только в том, если объект у вас есть позволяет получать предметы, используйте collections.abc.Sequence:

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

если вы строго заинтересованы в объекты, которые позволяют получать, устанавливать и удаление элементов (i.e mutable последовательности), вы бы выбрали collections.abc.MutableSequence.

там определены многие другие Азбуки,Mapping для объектов, которые могут быть использованы как карты, Iterable, Callable и так далее. Полный список всего этого можно увидеть в документация collections.abc.


будьте осторожны с помощью isinstance

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

но типа

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