3

I was wondering why Python's typing module does not support isinstance(<obj>, Any) and raises a TypeError. I would expect it to always return True. Is there a specific reason why it does not always return True?

  • The TypeError is raised here.
  • Example of the TypeError:
>>> from typing import Any
>>> isinstance(1, Any)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/peter/miniconda3/envs/prefect_utils/lib/python3.9/typing.py", line 338, in __instancecheck__
    raise TypeError(f"{self} cannot be used with isinstance()")
TypeError: typing.Any cannot be used with isinstance()
Peter
  • 746
  • 6
  • 22
  • 4
    Because why would you be doing this check in the first place if the answer is always `True`? – deceze Jun 18 '21 at 07:52
  • 1
    If you want a type that any object will be regarded as an instance of with `isinstance`, consider `object`. – khelwood Jun 18 '21 at 08:02
  • 2
    @deceze: that logic would lead me to believe the dunder checks would then just return true unconditionally, not raise an exception. I think there are likely undesirable implications to doing that. – paxdiablo Jun 18 '21 at 08:03
  • 2
    Most things in typing are not intended for runtime type checking. Any is no exception. Most types cannot be accurately checked dynamically, so typing avoids pretending it's possible. – MisterMiyagi Jun 18 '21 at 08:03
  • @deceze : because I am checking various types (not only, but including, `Any`) at runtime to check if a given object is indeed the given type. It would make sense in this case for `isinstance(obj, Any)` to return `True` instead of raise an exception. And this would also be a valid reason imo to have it always return `True`. – Peter Jun 19 '21 at 06:12

2 Answers2

5

The Any class docstring seems to state the reason:

"""Special type indicating an unconstrained type.

- Any is compatible with every type.
- Any assumed to have all methods.
- All values assumed to be instances of Any.

Note that all the above statements are true from the point of view of
static type checkers. At runtime, Any should not be used with instance
or class checks.
"""

def __instancecheck__(self, obj):
    raise TypeError("Any cannot be used with isinstance().")

def __subclasscheck__(self, cls):
    raise TypeError("Any cannot be used with issubclass().")

It's likely that treating these objects as an actual instance or subclass may lead to problems if they don't provide exactly what the instance or subclass should. Instead, they "fake" the fact they can be anything but not so much as to cause damage by being treated that way in the type hierarchy.

paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
3

Most things in typing are not intended for runtime type checking. Most types cannot be sensibly checked dynamically, so typing avoids pretending it's possible.


The Any type is not a proper type – it is compatible with any type in any usage. Depending on the use, it can be both the super and sub type of another type.
Most prominently, Any supports all operations. Therefore, isinstance(x, Any) == True would mean that x supports all operations, regardless of x' concrete type. This is not sensible for most proper types.


Consider for example checking an integer as an "instance of Any", which implies it supports slicing:

x = 3
if isinstance(x, Any):  # x supports any operation in this block
    print(x[:3])        # slicing is part of "all operations"
MisterMiyagi
  • 44,374
  • 10
  • 104
  • 119
  • 1
    This makes sense to me, thanks. For reference: This SO answer on a related question explained the problem in more detail by comparing `Any` to `object`: https://stackoverflow.com/a/39817126/919431 – Peter Jun 19 '21 at 06:32