선택적 유형 힌트는 어떻게 사용해야합니까?


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

따라서 두 예의 경우 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[](A)에 Union[], 또는 단지 추가 None받는이 Union[]. 그래서 Optional[Union[str, int]]Union[str, int, None]정확히 같은 일이다.

개인적으로 저는 기본값을 설정하는 데 사용하는 키워드 인수의 유형을 설정할 때 항상 사용을 고수 합니다. 이것은 더 나은 허용 이유를 설명 합니다. 또한 부품을 별도의 유형 별칭으로 이동 하거나 인수가 필수가 될 경우 나중에 부품을 제거하는 것이 더 쉽습니다 .Optional[]= NoneNoneUnion[...]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[]했기 때문에을 별칭으로 이동하는 리팩터링 이 훨씬 쉬워졌습니다 . 값은 값의 일부가 아니다, 모든 후 '는 SubWidget ID'아닌 플래그 값의 부재를 의미한다.Optional[...]Union[str, int, None]NoneNone

참고 : 코드가 Python 3.9 이상 만 지원해야하는 경우가 아니면 포함해야하는 유형에 대해 아무 것도 말할 수 없으므로 유형 힌팅에서 표준 라이브러리 컨테이너 유형을 사용하지 않는 것이 좋습니다. 그래서 대신 dict하고 list, 사용 typing.Dicttyping.List각각. 컨테이너 유형 에서만 읽을 때 변경 불가능한 추상 컨테이너 유형을 허용 할 수 있습니다. 목록과 튜플는 Sequence동안, 객체 dictA는 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

Python 3.9 이상에서 표준 컨테이너 유형은 모두 유형 힌트에서 사용할 수 있도록 업데이트되었습니다 . PEP 585를 참조하세요 . 그러나 지금 동안, 사용 dict[str, int]하거나 list[Union[int, str]], 당신은 여전히 더 많은 표현 사용할 수 있습니다 MappingSequence(그들은 '읽기 전용'으로 처리됩니다), 그리고 기능이 작동 것이라고 함수 내용을 변이되지 않음을 나타 내기 위해 주석을 각각 매핑 또는 시퀀스로 작동하는 모든 개체.


@MartijnPieters 우리가 수입 할 필요가 없습니다 DictList입력 및 쓰기에서 Optional[Dict]하고 Optional[List]대신 Optional[dict]...
알리레자

@Alireza 예, 나는 이미 내 대답에 명시합니다. : 대한 봐 사이드 참고 : 당신은 그들이 있어야합니다 어떤 종류에 대해 아무것도 말할 수있는 당신은, 그러나 암시 유형의 표준 라이브러리 컨테이너 유형을 사용하지 않도록 할
마티 피에 터스

내가 틀렸다면 정정하되 3.9는 유형 힌트 (vs. , ) 를 허용 list하고 사용할 dict수 있습니다 . python.org/dev/peps/pep-0585ListDict
user48956

2
@ user48956 : 3.9에 섹션을 추가했습니다.
Martijn Pieters

3

mypy 타이핑 모듈 문서 에서 직접 .

  • “Optional [str]은 Union [str, None]의 약자 또는 별칭입니다. 기능 서명을 좀 더 깔끔하게 보이게하기위한 편의상 대부분 존재합니다.”
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.