概要
Python にはタイプヒントという機能がありこれを使ってある程度の型指定を行うことができます 今回は型の指定方法や静的チェックを試してみました
環境
- macOS 11.3.1
- Python 3.8.7
- mypy 0.812
Type Hints
あくまでもヒントとして型を記述することができます 例えば以下のような感じで引数や返り値に型を指定することができます
class User():
def __init__(self, name: str, age: int):
self.name = name
self.age = age
def change_name(self, name: str):
self.name = name
def add_age(self, age: int) -> int:
return self.age + age
def show_profile(self):
print(self.name)
print(self.age)
user = User("hawk", 10)
user.change_name("snowlog")
user.add_age(2)
user.show_profile()
しかしあくまでもヒントでしかないので定義した型以外の型でも実行できてしまいます
user = User(-1, 10)
user.change_name(-2)
print(user.add_age("error"))
Traceback (most recent call last):
File "test.py", line 23, in <module>
print(user.add_age("error"))
File "test.py", line 10, in add_age
return self.age + age
TypeError: unsupported operand type(s) for +: 'int' and 'str'
事前に型チェックする
mypy というツールを使うと事前に型チェックできるため上記のように型が間違っている場合にエラーとなっている箇所を見つけることができます
- pip3 install mypy
これで先程のコードに対してチェックすると型が違っているというエラーを確認できます
- mypy test.py
test.py:21: error: Argument 1 to "User" has incompatible type "int"; expected "str"
test.py:22: error: Argument 1 to "change_name" of "User" has incompatible type "int"; expected "str"
test.py:23: error: Argument 1 to "add_age" of "User" has incompatible type "str"; expected "int"
Found 3 errors in 1 file (checked 1 source file)
型エイリアスを使う
プリミティブな型を独自の型名として使うことができます あくまでも元の型として扱われます コードのリファクタなどに使えます
my_int = int
class User():
def __init__(self, name: str, age: int):
self.name = name
self.age = age
def change_name(self, name: str):
self.name = name
def add_age(self, age: int) -> my_int:
return self.age + age
def show_profile(self):
print(self.name)
print(self.age)
user = User("hawk", 10)
print(user.add_age(2).__class__)
NewType を使う
新しい型を定義します エイリアスとは異なり実際に型チェックに引っかかります
from typing import NewType
my_int = int
Name = NewType('Name', str)
Age = NewType('Age', int)
class User():
def __init__(self, name: str, age: int):
self.name = name
self.age = age
def change_name(self, name: Name):
self.name = name
def add_age(self, age: Age) -> my_int:
return self.age + age
def show_profile(self):
print(self.name)
print(self.age)
user = User("hawk", 10)
name = Name("snowlog")
user.change_name(name)
age = Age(2)
print(user.add_age(age))
user.show_profile()
もし以下のようにちゃんと型を生成してから指定していない場合は型チェックでエラーになります
user = User("hawk", 10)
# name = Name("snowlog")
user.change_name("snowlog")
age = Age(2)
print(user.add_age(age))
user.show_profile()
test2.py:24: error: Argument 1 to "change_name" of "User" has incompatible type "str"; expected "Name"
Found 1 error in 1 file (checked 1 source file)
その他
ジェネリクス、Any 型、Optional 型などもあるのでかなり正確に型付けを行うことができます
0 件のコメント:
コメントを投稿