How do you alias a type in Python?
In some (mostly functional) languages you can do something like this:
type row = list(datum)
or
type row = [datum]
So that we can build things like this:
type row = [datum]
type table = [row]
type database = [table]
Is there a way to do this in Python? You could do it using classes, but Python has quite some functional aspects so I was wondering if it could be done an easier way.
Since Python 3.5 you may use typing module.
Quoting docs, A type alias is defined by assigning the type to the alias:
Vector = List[float]
To learn more about enforcing types in Python you may want to get familiar with PEPs: PEP483 and PEP484.
Python historically was using duck-typing instead of strong typing and hadn't built-in way of enforcing types before 3.5 release.
The accepted answer from @Lukasz is what we would need for most of the time. But for cases where you need the alias to be a distinct type on its own, you might need to use typing.NewType
as documented here: https://docs.python.org/3/library/typing.html#newtype
from typing import List, NewType
Vector = NewType("Vector", List[float])
One particular use case is if you are using the injector
library and you need to inject the aliased new type rather than the original type.
from typing import NewType
from injector import inject, Injector, Module, provider
AliasRawType = str
AliasNewType = NewType("AliasNewType", str)
class MyModule(Module):
@provider
def provide_raw_type(self) -> str:
return "This is the raw type"
@provider
def provide_alias_raw_type(self) -> AliasRawType:
return AliasRawType("This is the AliasRawType")
@provider
def provide_alias_new_type(self) -> AliasNewType:
return AliasNewType("This is the AliasNewType")
class Test1:
@inject
def __init__(self, raw_type: str): # Would be injected with MyModule.provide_raw_type() which is str. Expected.
self.data = raw_type
class Test2:
@inject
def __init__(self, alias_raw_type: AliasRawType): # Would be injected with MyModule.provide_raw_type() which is str and not MyModule.provide_alias_raw_type() which is just a direct alias to str. Unexpected.
self.data = alias_raw_type
class Test3:
@inject
def __init__(self, alias_new_type: AliasNewType): # Would be injected with MyModule.provide_alias_new_type() which is a distinct alias to str. Expected.
self.data = alias_new_type
injector = Injector([MyModule()])
print(injector.get(Test1).data, "-> Test1 injected with str")
print(injector.get(Test2).data, "-> Test2 injected with AliasRawType")
print(injector.get(Test3).data, "-> Test3 injected with AliasNewType")
Output:
This is the raw type -> Test1 injected with str
This is the raw type -> Test2 injected with AliasRawType
This is the AliasNewType -> Test3 injected with AliasNewType
Thus to correctly inject the proper provider when using the injector
library, you would need the NewType
aliasing.
Since Python 3.10, the TypeAlias annotation is available in the typing
module.
It is used to explicitly indicate that the assignment is done to generate a type alias. For example:
Point: TypeAlias = Tuple[float, float]
Triangle: TypeAlias = Tuple[Point, Point, Point]
You can read more about the TypeAlias
annotation on the PEP 613 that introduced it.