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
