I suspect the answer is yes, but I wanted to ask just to be clear. If I have a function that expects to use, for example, a numpy
object, but I am not using numpy
directly in my module, can I use a forward reference to type hint my argument rather than import numpy
directly?
In other words (assuming Python 3.7 ), can I do this
# forward-reference.py
def my_func(arr: "np.ndarray") -> int:
# does some operations with arr
instead of this
# direct-import.py
import numpy as np
def my_func(arr: np.ndarray) -> int:
# do some operations on arr...
I can't imagine the core developers would require programmers to import a module simply for type hinting. My pylint
or flake8
linters would correctly pick those up as unused modules and I think all those extra imports would be quite redundant.
Edit
To test, I created two files: demo1.py
and demo2.py
(both live in the same directory):
demo1.py
# demo1.py
import numpy as np
from demo2 import my_func
if __name__ == "__main__":
a = np.array([1, 2, 3])
print(my_func(a))
demo2.py
# demo2.py
def my_func(arr: "np.ndarray") -> int:
return arr[0]
Running mypy
on demo1.py
gives no errors, but running it on demo2.py
with either numpy.ndarray
gives the error:
demo2.py:1: error: Name "numpy" is not defined
or np.ndarray
gives the error:
demo2.py:1: error: Name "np" is not defined
So if I were designing a module demo2.py
first, intending it to accept numpy arrays before I designed demo1.py
, mypy
would give an error.
Is there a better/"proper" way to handle the above situation?
CodePudding user response:
No, you can't.
You will need to have the names in scope (after all, you could have done a Ministry of Silly Imports and done import math as np
), but you can use typing.TYPE_CHECKING
if you don't want to really import the module:
from typing import TYPE_CHECKING
if TYPE_CHECKING: # never true unless you're a type checker
import numpy as np
def my_func(arr: "np.ndarray") -> int:
pass # does some operations with arr
Beyond that, type checkers don't (or shouldn't) care what you call the things; they'll resolve the symbols to their best capability, and e.g. this should work: (but please don't...)
from typing import TYPE_CHECKING
if TYPE_CHECKING: # never true unless you're a type checker
import numpy as noooooooooop
bazoop = noooooooooop.ndarray
glerp = int
def my_func(arr: "bazoop") -> "glerp":
pass # does some operations with arr