I see a lot of Python people trying to tackle the C-esque problem of forward declaration for type-hinting purposes. There is much following of the
typing module’s example, loading modules and names, ballooning globals(), just to be able to hint names from them, and lots of comment-hinting and other workarounds.
It feels especially wasteful in code that makes no use of runtime introspection.
Perhaps a Python solution to a Python problem might be better.
import def <non-wildcard import statement>; from <path> import def <non-wildcard list>;
Other wordings might be viable, I chose
import def because it is import related and
def is a keyword
>>> import def File "<stdin>", line 1 import def
and we’re only seeking to import the definition of things (forward definition, if you will).
This statement WOULD NOT impact on the globals() namespace, it WOULD NOT [immediately] attempt to load anything.
Any runtime side-effects WOULD BE deferred to the point where someone tries to perform runtime introspection.
Meanwhile, type-analyzers can use this to recognize where to obtain hinting information from.
# Current code from typing import Union # for emphasis, aware it is deprecated. from . Adaptors import Base # None of these are actually used in this module. from . Adaptors.Mesh import Mesh from . Adaptors.Shader import Shader from . Adaptors.Texture import Texture # None of these are actually used in this module. from Packages.Converters.ConvertMesh import MeshConverter as MeshC from Packages.Converters.ConvertShader import ShaderConverter as ShaderC from Packages.Converters.ConvertTexture import TextureConverter as TextureC def process(asset: Union[Mesh, Shader, Texture], converter: Union[MeshC, ShaderC, TextureC]): if Base.legal_conversion(asset, converter): converter.convert(asset) print(globals())
The globals printed here would include
process, Union, Mesh, Shader, Texture, MeshC, ShaderC and TextureC, despite being entirely unneccesary.
If this becomes the following, meaning none of the ‘import def’ symbols would be available in the module’s namespace.
from typing import def Union from . Adaptors import Base # actual import from . Adaptors.Mesh import def Mesh from . Adaptors.Shader import def Shader from . Adaptors.Texture import def Texture from Packages.Converters.ConvertMesh import def MeshConverter as MeshC from Packages.Converters.ConvertShader import def ShaderConverter as ShaderC from Packages.Converters.ConvertTexture import def TextureConverter as TextureC def process(asset: Union[Mesh, Shader, Texture], converter: Union[MeshC, ShaderC, TextureC]): if Base.legal_conversion(asset, converter): converter.convert(asset) print(globals())
then the only non-default global would be ‘process’ - none of the others would appear in the namespace because they are purely type hinting definitions.
- Can this be implemented to solve inter-module circular dependencies?
- Can we create declaration imports?
– Something similar to all in index? E.g. def?
– ‘from Module import def *’ to allow creation of forward-declaration ‘headers’?
- How do I define an alias without a real import?
– How do you write Tree = Iterable[Tuple[Path, DirEntry]] without importing all of these?