ããã¯ããªã«ãããããŠæžãããã®ïŒ
ç°¡åãªPythonã¹ã¯ãªãããæžãæã¯Emacsã§lsp-modeã䜿ã£ãŠããããšãå€ãã®ã§ãããåå®çŸ©ãè£å®ããŠããã®ãããç®ã«å
¥ãã®ã§
ãã£ãããªã®ã§å°ãæŒãããŠãããããªãšæããŸããŠã
Pythonã®åãã³ã
Pythonã®åãã³ãã«é¢ããããã¥ã¡ã³ãã¯ãã¡ãã
typing --- 型ヒントのサポート — Python 3.10.15 ドキュメント
åèïŒ
Python最新バージョン対応!より良い型ヒントの書き方 | gihyo.jp
詳现ãªä»æ§ã¯PEP 484ã
PEP 484 – Type Hints | peps.python.org
å°å ¥ã«é¢ãã説æã¯PEP 483ã«ãããŸãã
PEP 483 – The Theory of Type Hints | peps.python.org
åãã³ãã䜿ã£ãäŸãèŠãŠã¿ãŸãããã
以äžã¯str
åã®name
ãåãåããstr
åã®æ»ãå€ãè¿ãé¢æ°ã§ãã
def greeting(name: str) -> str: return 'Hello ' + name
ãããªæãã§å€æ°ã®åã¯:
ã®åŸãã«æžããé¢æ°ã®æ»ãå€ã®åã¯->
ã®åŸãã«æžãããã§ãã
ããã€ãç¹åŸŽçãªãã®ãèŠãŠã¿ãŸãããã
- typing --- åãã³ãã®ãµããŒã / åãšã€ãªã¢ã¹
- ããåã®ãšã€ãªã¢ã¹ãå®çŸ©
- typing --- åãã³ãã®ãµããŒã / NewType
- ããåããæ°ããåãäœæãããæ°ããåã¯å ã ã®åã®ãµãã¯ã©ã¹ã®ããã«æ±ããã
- typing --- åãã³ãã®ãµããŒã / åŒã³åºãå¯èœãªããžã§ã¯ã
- é¢æ°ãå€æ°ã«ãã€ã³ãããéã®åå®çŸ©
collections.abc.Callable
ã䜿ã
- typing --- åãã³ãã®ãµããŒã / ãžã§ããªã¯ã¹
- ã³ã³ããåã®ãªããžã§ã¯ãã«åæ å ±ãæå®ãã
- 䜿ãæ¹ã«ãã£ãŠã¯
typing
ã¢ãžã¥ãŒã«ãå¿ èŠ - çµã¿èŸŒã¿åã§ããžã§ããªã¯ã¹ã䜿ãããã®ããã
- ãŠãŒã¶ãŒã«ãå®çŸ©å¯èœ
- typing --- åãã³ãã®ãµããŒã / Any å
- ãã¹ãŠã®åãšäºææ§ã®ããç¹å¥ãªçš®é¡ã®å
æå®ããåã¯ãåºæ¬çã«ã¯çµã¿èŸŒã¿åã®ãã®ã§ããã
ãŸããtyping
ã¢ãžã¥ãŒã«ã䜿ãããšã§åå®çŸ©ã«äœ¿ããå
容ãå¢ããŸããäžéšãèŒããŠãããŸãããã
- ç¹æ®åä»ãããªããã£ã
- ç¹æ®å
typing.Any
typing.NoReturn
typing.TypeAlias
- ç¹æ®åœ¢åŒ
typing.Tuple
typing.Union
typing.Optional
typing.Callable
collections.abc.Callable
ã䜿ãããš
typing.Concatenate
class typing.Type
typing.Literal
typing.ClassVar
typing.Final
typing.Annotated
typing.TypeGuard
- Building generic types
- ...
- Other special directives
- ...
- ç¹æ®å
- Generic concrete collections
- ...
- æœè±¡åºåºã¯ã©ã¹
- ...
æããŠãããšããªããªãã®ã§ãéäžãã端æããŸããâŠã
ã¡ãªã¿ã«ãPythonã§ã¯åãã³ããå¿ é ã«ããã€ããã¯ãªããåçåä»ãèšèªã§ããããšã¯å€ãããªãããã§ãã
It should also be emphasized that Python will remain a dynamically typed language, and the authors have no desire to ever make type hints mandatory, even by convention.
PEP 484 â Type Hints / Rationale and Goals / Non-goals
ãã£ãŠãåãã³ãã¯å®è¡æã«ã¯æ©èœããã誀ã£ãåãæå®ããŠããµã€ãã«å®è¡ã§ããŸãã
bad_type.py
def add(a: int, b: int) -> int: return a + b print(add("foo", "bar"))
$ python3 bad_type.py foobar
ãšã¯ãããlsp-modeãPyCharmãšãã£ãåãã³ããå©çšã§ããç°å¢ã§ã¯ã誀ã£ãåãæå®ãããšèŠåã衚瀺ãããŸãã
Mypy
Mypyã¯Pythonã®åãã§ãã¯ããŒã«ã§ãã
mypy - Optional Static Typing for Python
GitHubãªããžããªãŒã¯ãã¡ãã
GitHub - python/mypy: Optional static typing for Python
äŸã¯ãã¡ãã«èšèŒããããtyping
ãããã§ã¯äœ¿ãããŠããŸãã
ããã¥ã¡ã³ãã¯ãã¡ãã
Getting startedã
Getting started - mypy 1.13.0 documentation
åã®æå®æ¹æ³ã¯ãã¡ãã®ããŒãã·ãŒããèŠãã®ãããã§ããããã
Type hints cheat sheet - mypy 1.13.0 documentation
䜿ãæ¹ã¯ããã§ãã¯å¯Ÿè±¡ã®ãã¡ã€ã«ããã£ã¬ã¯ããªãæå®ããŠå®è¡ããããã§ãã
$ mypy foo.py bar.py some_directory
The mypy command line - mypy 1.13.0 documentation
èšå®ãã¡ã€ã«ãå®çŸ©ã§ããã¿ããã§ããã
The mypy configuration file - mypy 1.12.1 documentation
Pythonã¹ã¯ãªããå ã«ã€ã³ã©ã€ã³ã§ãã®ãã¡ã€ã«ã«å¯Ÿããèšå®ãæžãããšãã§ããããã§ãâŠã
Inline configuration - mypy 1.13.0 documentation
ä»åã¯Mypyã¯å°ãè©ŠããŠã¿ããããã«ããŸãããã
ç°å¢
ä»åã®ç°å¢ã¯ãã¡ãã
$ python3 --version Python 3.10.12 $ pip3 --version pip 22.0.2 from /usr/lib/python3/dist-packages/pip (python 3.10)
Pythonã®åãã³ããè©ŠããŠã¿ã
ããã§ã¯ãåãã³ããè©ŠããŠã¿ãŸãããã
ãã£ãšäŸãã
ype_hint_getting_started.py
## strå message: str = "Hello Python!!" ## boolå contains_python: bool if "Python" in message: contains_python = True else: contains_python = False ## list[str] programming_languages: list[str] = ["Python", "Java", "JavaScript", "TypeScript", "C#"] for language in programming_languages: print(language) ## é¢æ°å®çŸ© def plus(a: int, b: int) -> int: return a + b ## ã¯ã©ã¹å®çŸ© class Person: first_name: str last_name: str age: int def __init__(self, first_name: str, last_name: str, age: int) -> None: self.first_name = first_name self.last_name = last_name self.age = age def say(self) -> str: return f"ååã¯{self.last_name}{self.first_name}ã§ã" katsuo = Person("ã«ããª", "磯é", 11) print(katsuo.say())
ããã§çµãã£ãŠããªããªã®ã§ãããã€ãæ°ã«ãªãããšãæžããŠãããŸãããã
èŸæžåã¯ïŒ
dict
ã«2ã€ååŒæ°ãæå®ããŸãã
people: dict[str, int] = { "磯éã«ããª": 11, "磯éã¯ã«ã¡": 9, "ãã°ç°ã¿ã©ãª": 3 }
foræã®äžã«ç»å Žããå€æ°ã®åã®æå®ã¯ïŒ
å
ã»ã©ã®ãµã³ãã«ã§ãããããã®ãæžããŸããããlanguage
å€æ°ã®åããããŸããã
## list[str] programming_languages: list[str] = ["Python", "Java", "JavaScript", "TypeScript", "C#"] for language in programming_languages: print(language)
ãã®language
ã®åãæå®ããã«ã¯ïŒãšã¡ãã£ãšæã£ããããã®ã§ãããããã¯æå®ããªããŠè¯ãããã§ããã«ãŒãã«äœ¿çšããŠãã
ã³ã¬ã¯ã·ã§ã³ã®åå®çŸ©ãã決ãŸã£ãŠããããã§ãã
ãã®èšè¿°ã§lsp-modeãªã©ã§ãlanguage
ã¯str
åã§ããããšãèªèããŠããŸãããåŸè¿°ã®Mypyã§ã®åãã§ãã¯ã§ãNGã«ãªããŸããã
æ»ãå€ã®ãªãé¢æ°ã®æ»ãå€ã®åã¯ïŒ
None
ã§ãã
def hello() -> None: print("Hello World")
ã³ã³ã¹ãã©ã¯ã¿ã®æ»ãå€ã®åã¯ïŒ
None
ã§ãã
def __init__(self, first_name: str, last_name: str, age: int) -> None:
ã¯ã©ã¹ã¡ãœããã§ãã®ã¯ã©ã¹ã®ã€ã³ã¹ã¿ã³ã¹ãè¿ãå Žåã®æ»ãå€ã®åã¯ïŒ
ãããªæãã§æžããããªãã®ã§ãã
class Person: first_name: str last_name: str age: int def __init__(self, first_name: str, last_name: str, age: int) -> None: self.first_name = first_name self.last_name = last_name self.age = age @classmethod def create(cls, first_name: str, last_name: str, age: int) -> Person: return cls(first_name, last_name, age)
ããã¯å®è¡ã§ããªãã£ããããŸãã
Traceback (most recent call last): File "/path/to/some_file.py", line 6, in <module> class Person: File "//path/to/some_file.py", line 17, in Person def create(cls, first_name: str, last_name: str, age: int) -> Person: NameError: name 'Person' is not defined
æååã«ããå¿ èŠãããã¿ããã§ãã
@classmethod def create(cls, first_name: str, last_name: str, age: int) -> "Person": return cls(first_name, last_name, age)
åãã³ãã®ããã¥ã¡ã³ãã§ã¯ãtyping.TypeVar
ã䜿ã£ãŠæ»ãå€ã§äœ¿ãåãå®çŸ©ããŠããŸãã
é¢æ°ãåãåãé¢æ°ãå®çŸ©ããã«ã¯ïŒ
collections.abc.Callable
ã䜿ããŸãã
from collections.abc import Callable ## åŒæ°ããã®é¢æ°ãåãåã def filter(languages: list[str], func: Callable[[str], bool]) -> list[str]: return [language for language in languages if func(language)] ## åŒæ°ãªãã®é¢æ°ãåãåã def hello(name_generator: Callable[[], str]) -> None: print(f"Hello {name_generator()}") print(filter(["Java", "JavaScript", "Python"], lambda l: "JavaScript" in l)) hello(lambda: "Callable" )
Mypyã䜿ã£ãŠã¿ã
æåŸã«Mypyã䜿ã£ãŠã¿ãŸãããã
ã€ã³ã¹ããŒã«ã
$ pip3 install mypy
ã€ã³ã¹ããŒã«ãããã©ã€ãã©ãªãŒã®äžèŠ§ã
$ pip3 list Package Version ----------------- ------- mypy 1.10.1 mypy-extensions 1.0.0 pip 22.0.2 setuptools 59.6.0 tomli 2.0.1 typing_extensions 4.12.2
æåã«æžãã誀ã£ãåãæå®ããŠé¢æ°ãåŒã³åºããŠããã¹ã¯ãªããã§è©ŠããŠã¿ãŸãããã
bad_type.py
def add(a: int, b: int) -> int: return a + b print(add("foo", "bar"))
ãããªæãã§æãããŸãã
$ mypy bad_type.py bad_type.py:4: error: Argument 1 to "add" has incompatible type "str"; expected "int" [arg-type] bad_type.py:4: error: Argument 2 to "add" has incompatible type "str"; expected "int" [arg-type] Found 2 errors in 1 file (checked 1 source file)
ã«ã¬ã³ããã£ã¬ã¯ããªé
äžãç¹å®ã®ãã£ã¬ã¯ããªé
äžã®ã¹ã¯ãªããããŸãšããŠæå®ãããå Žåã¯ã以äžã®ããã«ãã£ã¬ã¯ããªãæå®ããã°
OKã§ãã
$ mypy . $ mypy [directory]
ãŸã--disallow-untyped-defs
ãªãã·ã§ã³ãè¿œå ããããšã§ãåæå®ã®ãªãå®çŸ©ããããšãšã©ãŒã«ã§ããŸãã
$ mypy --disallow-untyped-defs bad_type.py
ããšãã°ããããã³ãŒããè¿œå ããŠå®è¡ãããš
def message(s): print(s)
åã¢ãããŒã·ã§ã³ããªããšæãããŸãã
bad_type.py:6: error: Function is missing a type annotation [no-untyped-def]
ãããªãšããã§ããããã
ãªãã±ïŒ åæ å ±ããªãå Žå
Mypyã䜿ã£ãŠåãã§ãã¯ãè¡ãéã«ãåæ å ±ããªãå Žåã¯ã¹ã¿ããã¡ã€ã«ãšãããã®ãäœæããå¿ èŠãããããã§ãã
Stub files - mypy 1.13.0 documentation
typeshedãšãããªããžããªãŒã«ã¯ãæšæºã©ã€ãã©ãªãŒããµãŒãããŒãã£æ§ã®ã©ã€ãã©ãªãŒãªã©ã®åæ
å ±ãå«ãŸããŠããã®ã§ããã¡ãã
䜿ãããšã«ãªãããã§ããã
GitHub - python/typeshed: Collection of library stubs for Python, with static types
ãã¡ãã«ã€ããŠã¯ããŸããããèŠãŠã¿ãããšæããŸãã
ãããã«
Pythonã§åãã³ããè©ŠããŠã¿ãŸãããåãããŠãMypyã䜿ã£ãŠã¿ãŸããã
ã¡ãã£ãšããå°å ¥çãªãã®ã§ããããä»ãŸã§å®å šã«é°å²æ°ã§åãã³ããèŠãŠããã®ã§ãã®æ©äŒã«ããçšåºŠåãåã£ãŠãããŠããã£ãããªãšã
Pythonã§åãã³ãã䜿ããã©ããã¯åŸ®åŠãªãšãããªæ°ãããŸãããå人çã«ã¯ããã§æžãã¹ã¯ãªããã«ã€ããŠã¯é©çšããŠãããããªãš
æã£ããããŠããŸãã