Is there a simple way to determine if a variable is a list, dictionary, or something else?
try
doesn't help with. For example, if you knew that a user could pass in a string or an array, both are index-able, but that index means something completely different. Simply relying on a try-catch in those cases will fail in unexpected and strange ways. One solution is to make a separate method, another to add a little type checking. I personally prefer polymorphic behavior over multiple methods that do almost the same thing...but that's just me :) - anyone There are two built-in functions that help you identify the type of an object. You can use type()
if you need the exact type of an object, and isinstance()
to check an object’s type against something. Usually, you want to use isinstance()
most of the times since it is very robust and also supports type inheritance.
To get the actual type of an object, you use the built-in type()
function. Passing an object as the only parameter will return the type object of that object:
>>> type([]) is list
True
>>> type({}) is dict
True
>>> type('') is str
True
>>> type(0) is int
True
This of course also works for custom types:
>>> class Test1 (object):
pass
>>> class Test2 (Test1):
pass
>>> a = Test1()
>>> b = Test2()
>>> type(a) is Test1
True
>>> type(b) is Test2
True
Note that type()
will only return the immediate type of the object, but won’t be able to tell you about type inheritance.
>>> type(b) is Test1
False
To cover that, you should use the isinstance
function. This of course also works for built-in types:
>>> isinstance(b, Test1)
True
>>> isinstance(b, Test2)
True
>>> isinstance(a, Test1)
True
>>> isinstance(a, Test2)
False
>>> isinstance([], list)
True
>>> isinstance({}, dict)
True
isinstance()
is usually the preferred way to ensure the type of an object because it will also accept derived types. So unless you actually need the type object (for whatever reason), using isinstance()
is preferred over type()
.
The second parameter of isinstance()
also accepts a tuple of types, so it’s possible to check for multiple types at once. isinstance
will then return true, if the object is of any of those types:
>>> isinstance([], (tuple, list, set))
True
Answered 2023-09-20 20:56:09
is
instead of ==
as the types are singletons - anyone isinstance
is the preferred form anyhow, so neither ==
or is
need be used. - anyone type
is the best answer. There are times when isinstance
is the best answer and there are times when duck typing is the best answer. It's important to know all of the options so you can choose which is more appropriate for the situation. - anyone type(foo) is SomeType
would be better than isinstance(foo, SomeType)
. - anyone isinstance
for your usecase (checking for a range of types) as well, and with as clean a syntax as well, which has the great advantage that you can capture subclasses. someone using OrderedDict
would hate your code to fail because it just accepts pure dicts. - anyone Use type()
:
>>> a = []
>>> type(a)
<type 'list'>
>>> f = ()
>>> type(f)
<type 'tuple'>
Answered 2023-09-20 20:56:09
It might be more Pythonic to use a try
...except
block. That way, if you have a class which quacks like a list, or quacks like a dict, it will behave properly regardless of what its type really is.
To clarify, the preferred method of "telling the difference" between variable types is with something called duck typing: as long as the methods (and return types) that a variable responds to are what your subroutine expects, treat it like what you expect it to be. For example, if you have a class that overloads the bracket operators with getattr
and setattr
, but uses some funny internal scheme, it would be appropriate for it to behave as a dictionary if that's what it's trying to emulate.
The other problem with the type(A) is type(B)
checking is that if A
is a subclass of B
, it evaluates to false
when, programmatically, you would hope it would be true
. If an object is a subclass of a list, it should work like a list: checking the type as presented in the other answer will prevent this. (isinstance
will work, however).
Answered 2023-09-20 20:56:09
try
... except
is a good solution when you want to deal with errors, but not when deciding on behavior based on type. - anyone On instances of object you also have the:
__class__
attribute. Here is a sample taken from Python 3.3 console
>>> str = "str"
>>> str.__class__
<class 'str'>
>>> i = 2
>>> i.__class__
<class 'int'>
>>> class Test():
... pass
...
>>> a = Test()
>>> a.__class__
<class '__main__.Test'>
Beware that in python 3.x and in New-Style classes (aviable optionally from Python 2.6) class and type have been merged and this can sometime lead to unexpected results. Mainly for this reason my favorite way of testing types/classes is to the isinstance built in function.
Answered 2023-09-20 20:56:09
__class__
is mostly OK on Python 2.x, the only objects in Python which don't have __class__
attribute are old-style classes AFAIK. I don't understand your Python 3 concern, by the way - on such version, just every object has a __class__
attribute that points to the proper class. - anyone Determine the type of an object with type
>>> obj = object()
>>> type(obj)
<class 'object'>
Although it works, avoid double underscore attributes like __class__
- they're not semantically public, and, while perhaps not in this case, the builtin functions usually have better behavior.
>>> obj.__class__ # avoid this!
<class 'object'>
Is there a simple way to determine if a variable is a list, dictionary, or something else? I am getting an object back that may be either type and I need to be able to tell the difference.
Well that's a different question, don't use 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)
This covers the case where your user might be doing something clever or sensible by subclassing str
- according to the principle of Liskov Substitution, you want to be able to use subclass instances without breaking your code - and isinstance
supports this.
Even better, you might look for a specific Abstract Base Class from collections
or 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)
Or, perhaps best of all, use duck-typing, and don't explicitly type-check your code. Duck-typing supports Liskov Substitution with more elegance and less verbosity.
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
to actually get an instance's class. isinstance
to explicitly check for actual subclasses or registered abstractions. Answered 2023-09-20 20:56:09
try
/except
instead of checking explicitly. - anyone __class__
, which, when the object is a Mock
is the only way I could get the supposed type, as type
would just say Mock
. There is a much better assertion to be had by using the return_value
of the mocked class, BTW. - anyone You can use type()
or isinstance()
.
>>> type([]) is list
True
Be warned that you can clobber list
or any other type by assigning a variable in the current scope of the same name.
>>> the_d = {}
>>> t = lambda x: "aight" if type(x) is dict else "NOPE"
>>> t(the_d) 'aight'
>>> dict = "dude."
>>> t(the_d) 'NOPE'
Above we see that dict
gets reassigned to a string, therefore the test:
type({}) is dict
...fails.
To get around this and use type()
more cautiously:
>>> import __builtin__
>>> the_d = {}
>>> type({}) is dict
True
>>> dict =""
>>> type({}) is dict
False
>>> type({}) is __builtin__.dict
True
Answered 2023-09-20 20:56:09
dict
string will also fail for lots of other code, like dict([("key1", "value1"), ("key2", "value2")])
. The answer for those kinds of issues is "Then don't do that". Don't shadow builtin type names and expect things to work properly. - anyone be careful using isinstance
isinstance(True, bool)
True
>>> isinstance(True, int)
True
but type
type(True) == bool
True
>>> type(True) == int
False
Answered 2023-09-20 20:56:09
using type()
x='hello this is a string'
print(type(x))
output
<class 'str'>
to extract only the str use this
x='this is a string'
print(type(x).__name__)#you can use__name__to find class
output
str
if you use type(variable).__name__
it can be read by us
Answered 2023-09-20 20:56:09
While the questions is pretty old, I stumbled across this while finding out a proper way myself, and I think it still needs clarifying, at least for Python 2.x (did not check on Python 3, but since the issue arises with classic classes which are gone on such version, it probably doesn't matter).
Here I'm trying to answer the title's question: how can I determine the type of an arbitrary object? Other suggestions about using or not using isinstance are fine in many comments and answers, but I'm not addressing those concerns.
The main issue with the type()
approach is that it doesn't work properly with old-style instances:
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
Executing this snippet would yield:
Are o and t instances of the same class? True
Which, I argue, is not what most people would expect.
The __class__
approach is the most close to correctness, but it won't work in one crucial case: when the passed-in object is an old-style class (not an instance!), since those objects lack such attribute.
This is the smallest snippet of code I could think of that satisfies such legitimate question in a consistent fashion:
#!/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
Answered 2023-09-20 20:56:09
In many practical cases instead of using type
or isinstance
you can also use @functools.singledispatch
, which is used to define generic functions (function composed of multiple functions implementing the same operation for different types).
In other words, you would want to use it when you have a code like the following:
def do_something(arg):
if isinstance(arg, int):
... # some code specific to processing integers
if isinstance(arg, str):
... # some code specific to processing strings
if isinstance(arg, list):
... # some code specific to processing lists
... # etc
Here is a small example of how it works:
from functools import singledispatch
@singledispatch
def say_type(arg):
raise NotImplementedError(f"I don't work with {type(arg)}")
@say_type.register
def _(arg: int):
print(f"{arg} is an integer")
@say_type.register
def _(arg: bool):
print(f"{arg} is a boolean")
>>> say_type(0)
0 is an integer
>>> say_type(False)
False is a boolean
>>> say_type(dict())
# long error traceback ending with:
NotImplementedError: I don't work with <class 'dict'>
Additionaly we can use abstract classes to cover several types at once:
from collections.abc import Sequence
@say_type.register
def _(arg: Sequence):
print(f"{arg} is a sequence!")
>>> say_type([0, 1, 2])
[0, 1, 2] is a sequence!
>>> say_type((1, 2, 3))
(1, 2, 3) is a sequence!
Answered 2023-09-20 20:56:09
As an aside to the previous answers, it's worth mentioning the existence of collections.abc
which contains several abstract base classes (ABCs) that complement duck-typing.
For example, instead of explicitly checking if something is a list with:
isinstance(my_obj, list)
you could, if you're only interested in seeing if the object you have allows getting items, use collections.abc.Sequence
:
from collections.abc import Sequence
isinstance(my_obj, Sequence)
if you're strictly interested in objects that allow getting, setting and deleting items (i.e mutable sequences), you'd opt for collections.abc.MutableSequence
.
Many other ABCs are defined there, Mapping
for objects that can be used as maps, Iterable
, Callable
, et cetera. A full list of all these can be seen in the documentation for collections.abc
.
Answered 2023-09-20 20:56:09
value = 12
print(type(value)) # will return <class 'int'> (means integer)
or you can do something like this
value = 12
print(type(value) == int) # will return true
Answered 2023-09-20 20:56:09
type()
is a better solution than isinstance()
, particularly for booleans
:
True
and False
are just keywords that mean 1
and 0
in python. Thus,
isinstance(True, int)
and
isinstance(False, int)
both return True
. Both booleans are an instance of an integer. type()
, however, is more clever:
type(True) == int
returns False
.
Answered 2023-09-20 20:56:09
In general you can extract a string from object with the class name,
str_class = object.__class__.__name__
and using it for comparison,
if str_class == 'dict':
# blablabla..
elif str_class == 'customclass':
# blebleble..
Answered 2023-09-20 20:56:09
For the sake of completeness, isinstance will not work for type checking of a subtype that is not an instance. While that makes perfect sense, none of the answers (including the accepted one) covers it. Use issubclass for that.
>>> class a(list):
... pass
...
>>> isinstance(a, list)
False
>>> issubclass(a, list)
True
Answered 2023-09-20 20:56:09