ããã¯ããªã«ãããããŠæžãããã®ïŒ
ç°¡åãªPythonã¹ã¯ãªãããæžãæã¯Emacsã§lsp-modeã䜿ã£ãŠããããšãå€ãã®ã§ãããåå®çŸ©ãè£å®ããŠããã®ãããç®ã«å
¥ãã®ã§
ãã£ãããªã®ã§å°ãæŒãããŠãããããªãšæããŸããŠã
Pythonã®åãã³ã
Pythonã®åãã³ãã«é¢ããããã¥ã¡ã³ãã¯ãã¡ãã
typing --- 型ヒントのサポート — Python 3.10.19 ドキュメント
åèïŒ
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.Anytyping.NoReturntyping.TypeAlias
- ç¹æ®åœ¢åŒ
typing.Tupletyping.Uniontyping.Optionaltyping.Callablecollections.abc.Callableã䜿ãããš
typing.Concatenateclass typing.Typetyping.Literaltyping.ClassVartyping.Finaltyping.Annotatedtyping.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.18.2 documentation
åã®æå®æ¹æ³ã¯ãã¡ãã®ããŒãã·ãŒããèŠãã®ãããã§ããããã
Type hints cheat sheet - mypy 1.18.2 documentation
äœ¿ãæ¹ã¯ããã§ãã¯å¯Ÿè±¡ã®ãã¡ã€ã«ããã£ã¬ã¯ããªãæå®ããŠå®è¡ããããã§ãã
$ mypy foo.py bar.py some_directory
The mypy command line - mypy 1.18.2 documentation
èšå®ãã¡ã€ã«ãå®çŸ©ã§ããã¿ããã§ããã
The mypy configuration file - mypy 1.18.2 documentation
Pythonã¹ã¯ãªããå ã«ã€ã³ã©ã€ã³ã§ãã®ãã¡ã€ã«ã«å¯Ÿããèšå®ãæžãããšãã§ããããã§ãâŠã
Inline configuration - mypy 1.18.2 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ã®åãã³ãã詊ããŠã¿ã
ããã§ã¯ãåãã³ãã詊ããŠã¿ãŸãããã
ãã£ãšäŸãã
type_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.18.2 documentation
typeshedãšãããªããžããªãŒã«ã¯ãæšæºã©ã€ãã©ãªãŒããµãŒãããŒãã£æ§ã®ã©ã€ãã©ãªãŒãªã©ã®åæ
å ±ãå«ãŸããŠããã®ã§ããã¡ãã
䜿ãããšã«ãªãããã§ããã
GitHub - python/typeshed: Collection of library stubs for Python, with static types
ãã¡ãã«ã€ããŠã¯ããŸããããèŠãŠã¿ãããšæããŸãã
ãããã«
Pythonã§åãã³ãã詊ããŠã¿ãŸãããåãããŠãMypyã䜿ã£ãŠã¿ãŸããã
ã¡ãã£ãšããå°å ¥çãªãã®ã§ããããä»ãŸã§å®å šã«é°å²æ°ã§åãã³ããèŠãŠããã®ã§ãã®æ©äŒã«ããçšåºŠåãåã£ãŠãããŠããã£ãããªãšã
Pythonã§åãã³ãã䜿ããã©ããã¯åŸ®åŠãªãšãããªæ°ãããŸãããå人çã«ã¯ããã§æžãã¹ã¯ãªããã«ã€ããŠã¯é©çšããŠãããããªãš
æã£ããããŠããŸãã