What's the canonical way to check for type in Python?

后端 未结 13 971
南旧
南旧 2020-11-21 07:34

What is the best way to check whether a given object is of a given type? How about checking whether the object inherits from a given type?

Let\'s say I have an objec

相关标签:
13条回答
  • 2020-11-21 08:03

    After the question was asked and answered, type hints were added to Python. Type hints in Python allow types to be checked but in a very different way from statically typed languages. Type hints in Python associate the expected types of arguments with functions as runtime accessible data associated with functions and this allows for types to be checked. Example of type hint syntax:

    def foo(i: int):
        return i
    
    foo(5)
    foo('oops')
    

    In this case we want an error to be triggered for foo('oops') since the annotated type of the argument is int. The added type hint does not cause an error to occur when the script is run normally. However, it adds attributes to the function describing the expected types that other programs can query and use to check for type errors.

    One of these other programs that can be used to find the type error is mypy:

    mypy script.py
    script.py:12: error: Argument 1 to "foo" has incompatible type "str"; expected "int"
    

    (You might need to install mypy from your package manager. I don't think it comes with CPython but seems to have some level of "officialness".)

    Type checking this way is different from type checking in statically typed compiled languages. Because types are dynamic in Python, type checking must be done at runtime, which imposes a cost -- even on correct programs -- if we insist that it happen at every chance. Explicit type checks may also be more restrictive than needed and cause unnecessary errors (e.g. does the argument really need to be of exactly list type or is anything iterable sufficient?).

    The upside of explicit type checking is that it can catch errors earlier and give clearer error messages than duck typing. The exact requirements of a duck type can only be expressed with external documentation (hopefully it's thorough and accurate) and errors from incompatible types can occur far from where they originate.

    Python's type hints are meant to offer a compromise where types can be specified and checked but there is no additional cost during usual code execution.

    The typing package offers type variables that can be used in type hints to express needed behaviors without requiring particular types. For example, it includes variables such as Iterable and Callable for hints to specify the need for any type with those behaviors.

    While type hints are the most Pythonic way to check types, it's often even more Pythonic to not check types at all and rely on duck typing. Type hints are relatively new and the jury is still out on when they're the most Pythonic solution. A relatively uncontroversial but very general comparison: Type hints provide a form of documentation that can be enforced, allow code to generate earlier and easier to understand errors, can catch errors that duck typing can't, and can be checked statically (in an unusual sense but it's still outside of runtime). On the other hand, duck typing has been the Pythonic way for a long time, doesn't impose the cognitive overhead of static typing, is less verbose, and will accept all viable types and then some.

    0 讨论(0)
  • 2020-11-21 08:03

    I think the cool thing about using a dynamic language like Python is you really shouldn't have to check something like that.

    I would just call the required methods on your object and catch an AttributeError. Later on this will allow you to call your methods with other (seemingly unrelated) objects to accomplish different tasks, such as mocking an object for testing.

    I've used this a lot when getting data off the web with urllib2.urlopen() which returns a file like object. This can in turn can be passed to almost any method that reads from a file, because it implements the same read() method as a real file.

    But I'm sure there is a time and place for using isinstance(), otherwise it probably wouldn't be there :)

    0 讨论(0)
  • 2020-11-21 08:04

    A simple way to check type is to compare it with something whose type you know.

    >>> a  = 1
    >>> type(a) == type(1)
    True
    >>> b = 'abc'
    >>> type(b) == type('')
    True
    
    0 讨论(0)
  • 2020-11-21 08:05

    For more complex type validations I like typeguard's approach of validating based on python type hint annotations:

    from typeguard import check_type
    from typing import List
    
    try:
        check_type('mylist', [1, 2], List[int])
    except TypeError as e:
        print(e)
    

    You can perform very complex validations in very clean and readable fashion.

    check_type('foo', [1, 3.14], List[Union[int, float]])
    # vs
    isinstance(foo, list) and all(isinstance(a, (int, float)) for a in foo) 
    
    0 讨论(0)
  • 2020-11-21 08:08

    To check if o is an instance of str or any subclass of str, use isinstance (this would be the "canonical" way):

    if isinstance(o, str):
    

    To check if the type of o is exactly str (exclude subclasses):

    if type(o) is str:
    

    The following also works, and can be useful in some cases:

    if issubclass(type(o), str):
    

    See Built-in Functions in the Python Library Reference for relevant information.

    One more note: in this case, if you're using Python 2, you may actually want to use:

    if isinstance(o, basestring):
    

    because this will also catch Unicode strings (unicode is not a subclass of str; both str and unicode are subclasses of basestring). Note that basestring no longer exists in Python 3, where there's a strict separation of strings (str) and binary data (bytes).

    Alternatively, isinstance accepts a tuple of classes. This will return True if o is an instance of any subclass of any of (str, unicode):

    if isinstance(o, (str, unicode)):
    
    0 讨论(0)
  • 2020-11-21 08:08

    isinstance(o, str) will return True if o is an str or is of a type that inherits from str.

    type(o) is str will return True if and only if o is a str. It will return False if o is of a type that inherits from str.

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