オプションタイプのヒントはどのように使用すればよいですか?


84

Optionalタイプヒントの使い方を理解しようとしています。PEP-484、私が使用することができます知っているOptionalためにdef test(a: int = None)どちらかとdef test(a: Union[int, None])def test(a: Optional[int])

しかし、次の例はどうですか?

def test(a : dict = None):
    #print(a) ==> {'a': 1234}
    #or
    #print(a) ==> None

def test(a : list = None):
    #print(a) ==> [1,2,3,4, 'a', 'b']
    #or
    #print(a) ==> None

Optional[type]と同じ意味のように思われる場合Union[type, None]、なぜ私Optional[]はまったく使用する必要がありますか?

回答:


120

Optional[...]は、の省略表記でUnion[..., None]あり、特定のタイプのオブジェクトが必要であるまたは必要であることをタイプチェッカーに通知しますNone。複雑な複合型またはそれ以上の型を含む、有効な型ヒントを...表します。デフォルト値のキーワード引数がある場合は常に、を使用する必要があります。Union[]NoneOptional

したがって、2つの例ではdictlistコンテナタイプがありますが、aキーワード引数のデフォルト値はそれNoneも許可されていることを示しているので、次を使用しますOptional[...]

from typing import Optional

def test(a: Optional[dict] = None) -> None:
    #print(a) ==> {'a': 1234}
    #or
    #print(a) ==> None

def test(a: Optional[list] = None) -> None:
    #print(a) ==> [1, 2, 3, 4, 'a', 'b']
    #or
    #print(a) ==> None

で使用Optional[]するUnion[]ことNoneと、に追加することの間に技術的な違いはないことに注意してくださいUnion[]。だからOptional[Union[str, int]]Union[str, int, None]まったく同じことです。

個人的には、デフォルト値を設定するために使用するキーワード引数のタイプを設定するときは常に使用Optional[]することに固執し= Noneます。これNoneは、許可される理由を文書化したものです。さらに、Union[...]パーツを別のタイプエイリアスに移動したりOptional[...]、引数が必須になった場合に後でパーツを削除したりするのが簡単になります。

たとえば、あなたが持っていると言う

from typing import Optional, Union

def api_function(optional_argument: Optional[Union[str, int]] = None) -> None:
    """Frob the fooznar.

    If optional_argument is given, it must be an id of the fooznar subwidget
    to filter on. The id should be a string, or for backwards compatibility,
    an integer is also accepted.

    """

次にUnion[str, int]、をタイプエイリアスにプルすることにより、ドキュメントが改善されます。

from typing import Optional, Union

# subwidget ids used to be integers, now they are strings. Support both.
SubWidgetId = Union[str, int]


def api_function(optional_argument: Optional[SubWidgetId] = None) -> None:
    """Frob the fooznar.

    If optional_argument is given, it must be an id of the fooznar subwidget
    to filter on. The id should be a string, or for backwards compatibility,
    an integer is also accepted.

    """

Union[]エイリアスに移動するためのリファクタリングは、のOptional[...]代わりに使用されたため、はるかに簡単になりましたUnion[str, int, None]None値は、それは、値の一部ではありません、すべての後に「サブウィジェットID」ではありませんNoneフラグに値がないことを意味しています。

補足:コードがPython 3.9以降のみをサポートする必要がある場合を除いて、タイプヒントで標準ライブラリコンテナータイプを使用することは避けてください。どのタイプを含める必要があるかについては何も言えません。したがって、dictとの代わりに、それぞれとlistを使用typing.Dicttyping.Listます。また、コンテナタイプから読み取るだけの場合は、不変の抽象コンテナタイプを受け入れることもできます。リストとタプルはSequenceオブジェクトですが、dictMappingタイプです。

from typing import Mapping, Optional, Sequence, Union

def test(a: Optional[Mapping[str, int]] = None) -> None:
    """accepts an optional map with string keys and integer values"""
    # print(a) ==> {'a': 1234}
    # or
    # print(a) ==> None

def test(a: Optional[Sequence[Union[int, str]]] = None) -> None:
    """accepts an optional sequence of integers and strings
    # print(a) ==> [1, 2, 3, 4, 'a', 'b']
    # or
    # print(a) ==> None

Pythonの3.9とアップでは、標準コンテナの種類は、すべての参照、タイプヒントでそれらを使用してサポートするように更新されましたPEP 585しかし、あなたが今いる間、することができます使用しdict[str, int]たりlist[Union[int, str]]、あなたはまだ、より表現を使用することもできますMappingし、Sequence(彼らは「読み取り専用」として扱われます)、および機能が作業することを関数が内容を変異されないことを示すために注釈をそれぞれマッピングまたはシーケンスとして機能するオブジェクト。


@MartijnPieters我々はインポートする必要はありませんDictし、Listタイピングや書き込みからOptional[Dict]Optional[List]代わりにOptional[dict]...
アリレザ

@Alirezaはい、そして私はすでに私の答えでそれを述べています。探してください:補足:タイプヒントで標準ライブラリコンテナタイプを使用することは避けたいと思いますが、どのタイプを含める必要があるかについては何も言えません
MartijnPieters

私が間違っているなら、私を修正しますが、3.9は可能にlistし、dictタイプヒント、(対の用途であることをListDict)。 python.org/dev/peps/pep-0585
user48956

2
@ user48956:3.9に関するセクションを追加しました。
MartijnPieters

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.