pexels-photo-602137.jpeg

PythonのEllipsis(...)とtype hints

 
0
このエントリーをはてなブックマークに追加
Kazuki Moriyama
Kazuki Moriyama (森山 和樹)

この記事で書くこと

  1. pythonのEllipsisとは
  2. Ellipsisのtype hintsでの使用例

前提知識

  1. Pythonのtype hintsについての簡単な知識
    1. スタブファイルが何者かなど
  2. Pythonについての基本的な知識
  3. 型システムについての基本的な理解

記事作成の動機

  1. スタブファイルで多用されている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: ...

ナンノコッチャ

  1. ellipsisとtype hintsについての記事がpep484くらいしか無い

Ellipsisとは

  1. ...の3点ドットで表されるシングルトンオブジェクト
    1. グーグラビリティが低い
  2. 「ellipsis」とは省略記号という意味
  3. python的にはなにか有るが、とりあえず省略していることを表す
    1. これがNoneとの違い
  4. 文でなく式、つまり値として利用できる
    1. これがpassとの違い

Type Hintsでの使用例

Callableでの引数リスト型の省略

PEP484
翻訳記事

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

スタブファイルでデフォルト引数が存在することを示す

PEP484
翻訳記事

スタブファイルである関数の引数にデフォルト値が存在することは定義しても、その値までは定義したくないことがある。
その場合デフォルト値を...で代用する。

def foo(x: AnyStr, y: AnyStr = ...) -> AnyStr: ...

引数yはデフォルト値として、""b""Noneのいずれも適切でなく、...が省略の意味として適切。

スタブファイルで関数本体を示す

PEP484
翻訳記事

スタブファイルの役目は関数やクラスのインターフェイスを示すことである。
その場合、関数の中身は記述する必要は無く、...で記述する。

    def __init__(self, func: Callable[..., _T], *args: Any, **kwargs: Any) -> None: ...

TypingモジュールのTuple型で任意の長さであることを示

PEP484
翻訳記事

型として、長さを定めないTuple型を指定したいときがある。
その場合Tuple[int, ...]でアノテーションする。
これはすべての要素がintで長さが任意のタプルを表す。

python2のType Hintsでの関数の引数型の省略

PEP484

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."""
info-outline

お知らせ

K.DEVは株式会社KDOTにより運営されています。記事の内容や会社でのITに関わる一般的なご相談に専門の社員がお答えしております。ぜひお気軽にご連絡ください。