确定对象的类型?

问题:确定对象的类型?

有没有一种简单的方法来确定变量是列表,字典还是其他?我回来的对象可能是任何一种类型,我需要能够分辨出两者之间的区别。

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.


回答 0

有两个内置函数可以帮助您识别对象的类型。您可以使用type() ,如果你需要一个对象的确切类型,并isinstance()检查对象的反对的东西类型。通常,您希望使用isistance()大多数时间,因为它非常健壮并且还支持类型继承。


要获取对象的实际类型,请使用内置type()函数。将对象作为唯一参数传递将返回该对象的类型对象:

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

当然,这也适用于自定义类型:

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

请注意,type()这只会返回对象的直接类型,而不能告诉您类型继承。

>>> type(b) is Test1
False

为此,您应该使用该isinstance功能。当然,这也适用于内置类型:

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

isinstance()通常是确保对象类型的首选方法,因为它还将接受派生类型。因此,除非您实际需要类型对象(无论出于何种原因),否则使用isinstance()优先于type()

第二个参数isinstance()还接受类型的元组,因此可以一次检查多个类型。isinstance如果对象属于以下任何类型,则将返回true:

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

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

回答 1

您可以使用type()

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

You can do that using type():

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

回答 2

使用tryexcept块可能更Pythonic 。这样一来,如果你有这叫声也像列表,或叫声也像字典类,它会循规蹈矩,无论什么的类型真的是。

为了明确起见,“告诉变量类型”之间的差异的首选方法是使用“ 鸭子类型”:只要变量响应的方法(和返回类型)是子例程所期望的,则将其视为期望的成为。例如,如果您有一个用getattr和重载方括号运算符的类setattr,但使用了一些有趣的内部方案,那么如果它试图模仿的话,它就适合充当字典。

type(A) is type(B)检查的另一个问题是,如果A是的子类B,它将以false编程方式求值,您希望它是的时间true。如果对象是列表的子类,则它应像列表一样工作:检查其他答案中提供的类型将防止此情况。(isinstance但是可以)。

It might be more Pythonic to use a tryexcept 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).


回答 3

在对象的实例上,您还具有:

__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和New-Style类(可从Python 2.6中可选)中,类和类型已合并,这有时会导致意外结果。主要是因为这个原因,我最喜欢的测试类型/类的方法是内置函数中的isinstance

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.


回答 4

确定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-根据Liskov Substitution的原理,您希望能够在不破坏代码的情况下使用子类实例-并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)

或者只是不明确地进行类型检查

或者,也许最重要的是,使用鸭式输入,而不要显式地检查代码。鸭式打字以更高的雅致和更少的冗长性支持Liskov Substitution。

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显式检查实际的子类或注册的抽象。
  • 只是避免在有意义的地方进行类型检查。

Determine the type of a Python object

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

type checking

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.

Use Abstractions

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 Just Don’t explicitly Type-check

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)

Conclusion

  • Use type to actually get an instance’s class.
  • Use isinstance to explicitly check for actual subclasses or registered abstractions.
  • And just avoid type-checking where it makes sense.

回答 5

您可以使用type()isinstance()

>>> type([]) is list
True

警告您可以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

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

回答 6

尽管问题已经很老了,但我偶然发现了这个问题,同时自己找到了正确的方法,并且我认为仍然需要澄清一下,至少对于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__方法最接近正确性,但是在一种关键情况下不起作用:当传入的对象是旧式(而不是实例!)时,因为这些对象缺少此类属性。

这是我能想到的最小的代码片段,以一致的方式满足了此类合法问题:

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

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

回答 7

小心使用isinstance

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

但是输入

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

be careful using isinstance

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

but type

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

回答 8

除了前面的答案外,值得一提的是collections.abc它的存在还包含一些补充鸭类的抽象基类(ABC)。

例如,与其明确地检查某物是否为列表,不如:

isinstance(my_obj, list)

如果您只想查看自己拥有的对象是否允许获取物品,可以使用collections.abc.Sequence

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

如果您对允许获取,设置删除项目(即可序列)的对象非常感兴趣,则可以选择collections.abc.MutableSequence

许多其它的ABC被定义在那里,Mapping对于可以使用的地图,对象IterableCallable,等等。有关这些文件的完整列表,请参见的文档collections.abc

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.


回答 9

通常,您可以从具有类名称的对象中提取字符串,

str_class = object.__class__.__name__

并进行比较

if str_class == 'dict':
    # blablabla..
elif str_class == 'customclass':
    # blebleble..

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

回答 10

在许多实际情况下,而不是使用typeisinstance也可以使用@functools.singledispatch,这是用来定义的通用功能功能实现用于不同类型的同一操作的多个函数构成)。

换句话说,当您具有如下代码时,您将希望使用它:

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

这是一个如何工作的小例子:

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

另外,我们可以使用抽象类一次覆盖几种类型:

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!

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!

回答 11

type()是比更好的解决方案isinstance(),特别是在booleans

TrueFalse只是关键字,平均10Python编写的。从而,

isinstance(True, int)

isinstance(False, int)

都回来了True。两个布尔值都是整数的实例。type()但是,它更聪明:

type(True) == int

返回False

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.