Определить тип объекта?
есть ли простой способ определить, является ли переменная списком, словарем или чем-то еще? Я возвращаю объект, который может быть любого типа, и мне нужно уметь отличать.
9 ответов
Вы можете сделать это с помощью 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