Python3.11の新機能 Python 3.11の新機能(その9) 型ヒントの新機能 - その他

(その1) CPython高速化計画(その2) 特殊化適応的インタープリタ(その3) 関数呼び出しのインライン化(その4) 例外グループとTaskGroup(その5) PEP-646 可変長ジェネリックス(その6) PEP-673 Self型(その7) PEP-681 データクラス変換(その8) PEP-655 TypedDictの要素ごとに省略可・不可を指定する(その9) その他の型ヒント関連機能(その10) 正規表現 - アトミックグループとPossessive指定子(その11) 標準ライブラリ(その12) Python本体の機能追加

型ヒント関連の新機能はまだ他にもありますが、ここでは以下の機能を紹介します。

TypedDict と NamedTuple で Generic を定義可能に

Python 3.10までは、TypedDictNamedTuple を定義するとき、派生元として Genericなど、他の型を指定できませんでした。

このため、TypedDictNamedTuple をジェネリックスとして使えなかったのですが、Python3.11ではこの制限が緩和され、Generic から継承できるようになりました。次のように、型変数を利用した型定義が可能です。

from typing import Generic, TypedDict, TypeVar, NamedTuple

T = TypeVar("T")

class TD(TypedDict, Generic[T]):
    item: T

td1: TD[int] = {'item': 100} # OK
td2: TD[int] = {'item': "100"} # Error
td3 = TD(item=[100])
reveal_type(td3)  # TD[list[int]]


class NP(NamedTuple, Generic[T]):
    elem: T

np1 = NP(elem=100)
reveal_type(np1)  # "NP[int]"

np2 : NP[str] = NP(elem=200) # Error

PEP-675 任意の文字列定数

これまでの型ヒントでは、Literal["SPAM"] を使って、決まった値の文字列定数のみ有効、という指定ができました。しかし、内容に関わらず、文字列定数なら有効 という指定はできませんでした。

Python 3.11では PEP-675 任意の文字列定数LiteralString が追加され、"文字列定数ならなんでもOK" のような、文字列定数の値のみを使えるように指定できるようになりました。

次の例では、関数 f(s: LiteralString) は、f("SELECT * FROM emp") のように文字列定数のみを指定できます。f(input()) のように、文字列定数以外の文字列を指定した場合は、エラーとなります。

import sys
from typing import LiteralString

def f(s: LiteralString):
    database.execute(s)

f("SELECT * FROM emp")  # 文字列定数なのでOK
f(input())  # 外部から入力した文字列なのでError

一般に、ファイルやネットワークなど、外部から取得した文字列は、SQLの一部としてデータベースにアクセスしたり、HTMLの一部としてWebブラウザで表示したりすると、セキュリティ上の問題が発生します。しかし、文字列定数はプログラムのソースコード中に直接書き込まれた文字列なので、外部からの攻撃に利用される可能性は低く、そのまま利用できます。LiteralString は、このような外部から取得した可能性がある危険な文字列と、安全な文字列定数を区別する場合に利用されます。

typing.reveal_type()

mypyなどで型チェックを行うとき、reveal_type() を使うと変数の型をコンソールに出力できます。

$ cat test.py
a = 100
reveal_type(a)

$ mypy test.py
test.py:2: note: Revealed type is "builtins.int"

複雑なアノテーションを記述するときに便利な機能ですが、一つ問題がありました。reveal_type() は mypy などの型チェッカでのみ実行可能な関数で、reveal_type() が残ったPythonスクリプトを実行すると、エラーとなってしまいます。このため、開発中に型を確認しながらテストを実行する場合には reveal_type() を入れたり消したりしなければならず、とても面倒でした。

Python 3.11では reveal_type()typing.reveal_type に追加され、こちらを使えば実行時にもエラーにならなくなりました。

$ cat test.py
import typing

a = 100
typing.reveal_type(a)

$ mypy test.py
test.py:2: note: Revealed type is "builtins.int"

$ python3.11 test.py
Runtime type is 'int'
Copyright © 2001-2022 python.jp Privacy Policy python_japan
Amazon.co.jpアソシエイト
Amazonで他のPython書籍を検索