Starting with python3.5, python also incorporates the concept of type hints.
To use it, use the built-in type or use ʻimport typing, and use
mypy` to check the type.
First, install the package to use mypy
.
$ pip install mypy
Create mypy.ini
as follows and enter the setting information there.
mypy.ini
[mypy]
python_version = 3.8
disallow_untyped_calls = True
disallow_untyped_defs = True
disallow_untyped_decorators = True
disallow_incomplete_defs = True
check_untyped_defs = True
pretty = True
[mypy-django.*]
ignore_missing_imports = True
See here (https://mypy.readthedocs.io/en/latest/config_file.html) for what you can configure.
The built-in type can be used as it is.
num: int = 1
float_num: float = 1.11
is_something: bool = True
text: str = 'hoge'
byte_str: bytes = b'fuga'
arr: list = [0, 1, 2, 3]
If you don't know what type goes into the variable, use ʻAny`. If this type is specified, no type checking will be done.
something: Any = Something()
The base class of all types, ʻobject, can be used in the same way, but ʻobject
is used to indicate that a value can be used as any type in a type-safe way, and ʻAny` is. Used to indicate that a value is dynamically typed.
If you use the dictionary type, use typing.Dict
.
dictionary: Dict[str, int] = {'hoge': 1, 'fuga': 2}
If you want to use tuple types, use typing.Tuple
.
something: Tuple[str, int] = ('hoge', 1)
If you want to use the set type, use typing.Set
.
The set type is a collection of unique items.
something: Set[int] = {6, 7}
If you want to use the sequence type, use typing.Sequence
.
The sequence type is a data structure for processing in order (sequential).
something: Sequence = [0, 1, 2]
If you want to use the iterator type, use typing.Iterator
.
The iterator type must be an iterable class and have __iter__ ()
.
something: Iterator = IterableClass()
If you want to use the mapping type, use typing.Mapping
.
The mapping type is a data structure for performing arbitrary key search, and is an Immutable type.
something: Mapping[str, int] = {'hoge': 1, 'fuga': 2}
If you want to use a union type, use typing.Union
.
Union types allow you to specify multiple types.
something_mapping: Mapping[str, int] = {'hoge': 1, 'fuga': 2}
something_union: Union[int, None] = something_mapping.get('hoge') # 1
something_union: Union[int, None] = something_mapping.get('piko') # None
typing.Optional
is an image in which None
of type typing.Union
is always selected.
something_mapping: Mapping[str, int] = {'hoge': 1, 'fuga': 2}
something_optional: Optional[int] = something_mapping.get('hoge') # 1
something_optional: Optional[int] = something_mapping.get('piko') # None
If you want to use a function, use typing.Callable
.
def something() -> bool:
return True
something_callable: Callable = something
Use typing.Literal
if you want to ensure that you only get a fixed value.
mode: Literal['r', 'rb', 'w', 'wb'] = 'r' # OK
mode: Literal['r', 'rb', 'w', 'wb'] = 'a' # NG
Use typing.AnyStr
if you want it to be used by a function that allows any kind of string without mixing it with other kinds of strings.
def concat(a: AnyStr, b: AnyStr) -> AnyStr:
return a + b
concat(u"foo", u"bar") #OK unicode is output
concat(b"foo", b"bar") #OK bytes are output
concat(u"foo", b"bar") #An error will occur because NG unicode and bytes are mixed.
You can define the old type with any type name.
Vector = List[float]
ConnectionOptions = Dict[str, str]
Address = Tuple[str, int]
Server = Tuple[Address, ConnectionOptions]
NewType
Use typing.NewType
to create different types.
UserId = NewType('UserId', int)
some_id = UserId(524313)
To use generic types:
T = TypeVar('T')
#This is the Generic function
#Any type can be used for l Sequence type
def first(l: Sequence[T]) -> T:
return l[0]
User-defined generic types can be used as follows:
T = TypeVar('T')
class LoggedVar(Generic[T]):
def __init__(self, value: T, name: str, logger: Logger) -> None:
self.name = name
self.logger = logger
self.value = value
def set(self, new: T) -> None:
self.log('Set ' + repr(self.value))
self.value = new
def get(self) -> T:
self.log('Get ' + repr(self.value))
return self.value
def log(self, message: str) -> None:
self.logger.info('%s: %s', self.name, message)
logger: LoggedVar[str] = LoggedVar('hoge', 'Test', Logger())
logger.get() #T is treated as str type
Once you want to change the defined type, cast it using typing.cast
.
In order to make the process as fast as possible, we intentionally inspect nothing at runtime.
a = [4]
b = cast(List[int], a)
c = cast(List[str], a) # [4]Is never a string, so if you want to convert it, add the conversion process yourself
If you want to use constants, use typing.Final
.
SOMETHING: Final[str] = 'Something'
How was that? I think that you can create a stronger application by making full use of the type. However, please note that specifying the type does not speed up the special processing. Some of them haven't actually been seen to work, so if you find something wrong, please let us know.
https://docs.python.org/ja/3/library/typing.html
Recommended Posts