srm
srm

Reputation: 597

Python type hint for arbitrary classes only (not class instances or any other non-class types)

I have a method which inspects and processes the source of arbitrary classes (classes only, not class instances or any other non-class types). The classes can be from any standard library, or 3rd party library, or user-defined classes.

But don't know of a correct way of annotating the type of the class argument using the typing module. I don't think typing.Type is the right one because it also applies to objects:

>>> class A: pass
>>> a = A()

>>> def test(cl: typing.Type) -> typing.Type:
...     return type(cl)

>>> test(A)
>>> type
>>> isinstance(A, typing.Type)
>>> True

>>> test(a)
>>> type
>>> isinstance(A, typing.Type)
>>> False

>>> test('A')
>>> str
>>> isinstance(A, typing.Type)
>>> False

Should annotations work this way? Isn't the point that annotated arguments should restrict the calling of the method to recognise only the correct types of arguments?

Upvotes: 0

Views: 1760

Answers (1)

Michael0x2a
Michael0x2a

Reputation: 63978

'Type' is indeed the right thing to use. For example, if you try type checking the following program using a type checker such as mypy...

from typing import Type

class A: pass

# To be even more precise, have the type signature be
# '(cls: Type[T]) -> Type[Type[T]]' where T is some TypeVar.
def test(cls: Type) -> Type:
    return type(cls)

a = A()

test(A)
test(a)
test('A')

...you end up with the following errors, which I believe is what you were expecting:

test.py:13: error: Argument 1 to "test" has incompatible type "A"; expected "Type[Any]"
test.py:14: error: Argument 1 to "test" has incompatible type "str"; expected "Type[Any]"
Found 2 errors in 1 file (checked 1 source file)

If you are asking why these type hints are not being checked by Python itself and why you need to use a 3rd party type checker, see What are type hints in Python 3.5?.

Upvotes: 2

Related Questions