Determine the type of an object?

后端 未结 13 2182
余生分开走
余生分开走 2020-11-22 05:50

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

相关标签:
13条回答
  • 2020-11-22 06:12

    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.
    0 讨论(0)
  • 2020-11-22 06:13

    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..
    
    0 讨论(0)
  • 2020-11-22 06:16

    You can do that using type():

    >>> a = []
    >>> type(a)
    <type 'list'>
    >>> f = ()
    >>> type(f)
    <type 'tuple'>
    
    0 讨论(0)
  • 2020-11-22 06:16

    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.

    0 讨论(0)
  • 2020-11-22 06:19

    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
    
    0 讨论(0)
  • 2020-11-22 06:21

    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.

    0 讨论(0)
提交回复
热议问题