首页 文章

确定对象的类型?

提问于
浏览
1492

有一种简单的方法可以确定变量是否是列表,字典或其他内容?我得到的对象可能是任何一种类型,我需要能够分辨出来 .

9 回答

  • 11

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

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

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

    >>> 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
    
  • 38

    您可以使用 type() 执行此操作:

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

    您可以使用 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
    
  • 4

    除了之前的答案之外,值得一提的是collections.abc的存在,其中包含几个补充鸭子类型的抽象基类(ABCs) .

    例如,而不是显式检查某些内容是否为列表:

    isinstance(my_obj, list)
    

    你可以,如果你只想看看你所拥有的物品是否允许获取物品,请使用collections.abc.Sequence

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

    如果你对允许获取,设置和删除项目(即可变序列)的对象严格感兴趣,你可以选择 collections.abc.MutableSequence .

    在那里定义了许多其他ABC, Mapping 用于可用作 Map 的对象, IterableCallable 等 . 所有这些的完整列表可以在the documentation for collections.abc.中看到

  • 1714

    小心使用isinstance

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

    但是输入

    type(True) == bool
    True
    >>> type(True) == int
    False
    
  • 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中可用)中,类和类型已合并,这有时会导致意外结果 . 主要是出于这个原因,我最喜欢的测试类型/类的方法是内置函数_197803 .

  • 16

    确定Python对象的类型

    使用 type 确定对象的类型

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

    尽管它有效,但要避免使用双重下划线属性,例如 __class__ - 它们在语义上不公开,并且虽然在这种情况下可能不是这样,但内置函数通常具有更好的行为 .

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

    类型检查

    有没有一种简单的方法来确定变量是列表,字典还是其他什么?我得到的对象可能是任何一种类型,我需要能够分辨出来 .

    那个's a different question, don'吨使用类型 - 使用 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 支持这一点 .

    使用抽象

    更好的是,您可能会从 collectionsnumbers 中查找特定的抽象基类:

    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)
    

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

    或者,也许最重要的是,使用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 显式检查实际的子类或注册的抽象 .

    • 并且只是避免在有意义的地方进行类型检查 .

  • 3

    虽然这些问题很老,但我偶然发现了一个正确的方法,我认为它仍然需要澄清, at least for Python 2.x (没有检查Python 3,但是因为问题出现在经典类中,这个版本已经消失了,这可能没关系) .

    在这里我_1972829的问题: how can I determine the type of an arbitrary object ?关于使用或不使用isinstance的其他建议在很多评论和答案中都很好,但我并没有解决这些问题 .

    type() 方法的主要问题是 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
    

    执行此代码段将产生:

    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
    
  • 148

    使用 try ... except 块可能更像Pythonic . 这样,如果你有一个像列表那样嘎嘎叫的类,或者像dict一样嘎嘎叫,那么无论它的类型是什么,它都会表现得很好 .

    为了澄清,变量类型之间的首选方法是duck typing:只要变量响应的方法(和返回类型)是您的子例程所期望的,就像对待它一样对待它 . 例如,如果你有一个用 getattrsetattr 重载括号运算符的类,但是使用了一些有趣的内部方案,那么如果's what it'试图模拟它,它就适合表现为字典 .

    type(A) is type(B) 检查的另一个问题是,如果 AB 的子类,则在编程方面,当您希望它是 true 时,它将计算为 false . 如果一个对象是列表的子类,它应该像列表一样工作:检查另一个答案中显示的类型将阻止这种情况 . ( isinstance 会起作用) .

相关问题