PythonのEllipsis(...)とtype hints
Kazuki Moriyama (森山 和樹)
この記事で書くこと
- pythonのEllipsisとは
- Ellipsisのtype hintsでの使用例
前提知識
- Pythonのtype hintsについての簡単な知識
- スタブファイルが何者かなど
- Pythonについての基本的な知識
- 型システムについての基本的な理解
記事作成の動機
- スタブファイルで多用されているellipsisの意味がわからなかった
例えばfunctoolsモジュールのpartialクラスのスタブファイル
class partial(Generic[_T]):
func = ... # type: Callable[..., _T]
args = ... # type: Tuple[Any, ...]
keywords = ... # type: Dict[str, Any]
def __init__(self, func: Callable[..., _T], *args: Any, **kwargs: Any) -> None: ...
def __call__(self, *args: Any, **kwargs: Any) -> _T: ...
ナンノコッチャ
- ellipsisとtype hintsについての記事がpep484くらいしか無い
Ellipsisとは
...
の3点ドットで表されるシングルトンオブジェクト- グーグラビリティが低い
- 「ellipsis」とは省略記号という意味
- python的にはなにか有るが、とりあえず省略していることを表す
- これが
None
との違い
- これが
- 文でなく式、つまり値として利用できる
- これが
pass
との違い
- これが
Type Hintsでの使用例
Callable
での引数リスト型の省略
Callable
型
コールバック関数のように引数に関数を渡したときの型。
from typing import Callable
def feeder(get_next_item: Callable[[], str]) -> None:
# Body
def async_query(on_success: Callable[[int], None],
on_error: Callable[[int, Exception], None]) -> None:
# Body
Callable
の引数リストの型の省略
コールバック関数の戻り値のみを記載したいときがある。
その場合、引数リストを...
で置き換える。
def partial(func: Callable[..., str], *args) -> Callable[..., str]:
# Body
スタブファイルでデフォルト引数が存在することを示す
スタブファイルである関数の引数にデフォルト値が存在することは定義しても、その値までは定義したくないことがある。
その場合デフォルト値を...
で代用する。
def foo(x: AnyStr, y: AnyStr = ...) -> AnyStr: ...
引数y
はデフォルト値として、""
、b""
、None
のいずれも適切でなく、...
が省略の意味として適切。
スタブファイルで関数本体を示す
スタブファイルの役目は関数やクラスのインターフェイスを示すことである。
その場合、関数の中身は記述する必要は無く、...
で記述する。
def __init__(self, func: Callable[..., _T], *args: Any, **kwargs: Any) -> None: ...
Tuple
型で任意の長さであることを示
Typingモジュールの
型として、長さを定めないTuple
型を指定したいときがある。
その場合Tuple[int, ...]
でアノテーションする。
これはすべての要素がint
で長さが任意のタプルを表す。
python2のType Hintsでの関数の引数型の省略
python2での型アノテーション
python2では型アノテーション機能が無い。
しかし、型アノテーション自体はコメントを使って書くことが推奨されている。
python2
def embezzle(self, account, funds=1000000, *fake_receipts):
# type: (str, int, *str) -> None
"""Embezzle funds from account using fake receipts."""
<関数本体をここに書く>
これは以下のpython3コードと等価。
python3
def embezzle(self, account: str, funds: int = 1000000, *fake_receipts: str) -> None:
"""Embezzle funds from account using fake receipts."""
<関数本体をここに書く>
戻り値のみ記載したい場合の省略
引数の型がまだ決定しておらず、戻り値のみ型を書きたいことがある。
そのとき、引数の型を...
で書く。
def send_email(address, sender, cc, bcc, subject, body):
# type: (...) -> bool
"""Send an email message. Return True if successful."""
引数が長いときの型を書く場所の分割
関数に引数が非常に多いとき、それらの型をコメントで書く場合コードが醜くなる。
その場合、引数の型と、戻り値の型を書く場所を別にするとスッキリする。
def send_email(address, # type: Union[str, List[str]]
sender, # type: str
cc, # type: Optional[List[str]]
bcc, # type: Optional[List[str]]
subject='',
body=None # type: List[str]
):
# type: (...) -> bool
"""Send an email message. Return True if successful."""