Home > Blockchain >  Python Forward References for Package Objects
Python Forward References for Package Objects

Time:10-12

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
  • Related