Optional
タイプヒントの使用方法を理解しようとしています。 PEP 434から、def test(a: int = None)
またはdef test(a: Union[int, None])
としてdef test(a: Optional[int])
にOptional
を使用できることがわかりました。
しかし、次の例はどうですか?
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[]
を使用する必要があるのですか?
Optional[...]
はUnion[..., None]
の略記法であり、特定のタイプのオブジェクトが必要であることをタイプチェッカーに伝える、またはNone
が必要です。 ...
は、複雑な複合型またはUnion[]
を含む有効な型のヒントを表します。デフォルト値None
を持つキーワード引数がある場合は常に、Optional
を使用する必要があります。
したがって、2つの例では、dict
およびlist
コンテナタイプがありますが、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[]
を使用することと、Union[]
に単にNone
を追加することとの間に技術的な違いはないことに注意してください。したがって、Optional[Union[str, int]]
とUnion[str, int, None]
はまったく同じものです。
個人的には、デフォルト値を設定するためにOptional[]
を使用するキーワード引数のタイプを設定するときに= None
を使用してalwaysに固執します。これは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
は値がないことを示すためのものです。
サイドノート:ただし、どのタイプを含める必要があるかについては何も言えないので、タイプヒントで標準ライブラリコンテナータイプを使用しないでください。そのため、dict
とlist
の代わりに、typing.List
とtyping.Dict
を使用します。そして、コンテナタイプからreadingのみの場合、不変の抽象コンテナタイプを受け入れることもできます。リストとタプルはSequence
オブジェクトですが、dict
はMapping
タイプです:
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