파이썬 3.5의 타입 힌트는 무엇입니까?


250

파이썬 3.5에서 가장 많이 언급 된 기능 중 하나는 타입 힌트 입니다.

의 예 타입 힌트 에서 언급 이 문서이것 또한 책임 타입 힌트를 사용하는 언급하면서. 누군가가 그들에 대해 그리고 언제 사용해야하는지, 그렇지 않을 때에 대해 더 설명 할 수 있습니까?


4
공식 변경 로그 에서 링크 된 PEP 484 를 살펴보십시오 .
Stefan

1
@AvinashRaj는 다음 릴리스에 대한에 좋은 토론이 벌어지고 여기에
Vaulstein

1
C-API 유스 케이스가이 PEP 484, 특히 Cython 및 Numba의 유형 힌트에 의해 완전히 무시되는 것은 유감입니다.
denfromufa

답변:


344

내가 읽고 제안 PEP (483)PEP 484을 시청 타입 힌팅에 귀도하여 프리젠 테이션을.

간단히 말해서 : 유형 힌트는 말 그대로 단어의 의미 입니다. 사용중인 객체의 유형을 암시합니다 .

파이썬 의 동적 인 특성 으로 인해 사용중인 객체 의 유형유추하거나 확인하는 것이 특히 어렵습니다. 이 사실은 개발자가 작성하지 않은 코드에서 정확히 무슨 일이 일어나고 있는지, 그리고 무엇보다도 많은 IDE (PyCharm, PyDev가 떠오름)에서 발견되는 형식 검사 도구에 대해 정확히 이해하기 어렵습니다. 객체의 유형에 대한 표시기가 없습니다. 결과적으로 그들은 프레젠테이션에서 언급 한 것처럼 약 50 %의 성공률로 유형을 추론하려고 시도합니다.


Type Hinting 프레젠테이션에서 두 가지 중요한 슬라이드를 가져 오려면

왜 타입 힌트인가?

  1. 유형 검사기를 도와줍니다. 개체가 어떤 형식인지 확인하면 개체를 형식 검사기가 쉽게 감지 할 수 있습니다.
  2. 문서화에 도움 : 코드를 보는 제 3자는 코드를받지 않고 코드를 사용하는 방법을 알고있을 것 TypeErrors입니다.
  3. IDE가보다 정확하고 강력한 도구를 개발할 수 있도록 지원 : 개발 환경은 객체의 유형을 알 때 적절한 방법을 제안하는 데 더 적합합니다. 어느 시점에서 일부 IDE 에서이 문제를 경험했을 수 있으며 .객체에 대해 정의되지 않은 메소드 / 속성 팝업이 나타납니다.

정적 유형 검사기를 사용해야하는 이유

  • 더 빨리 버그 찾기 : 이것은 자명 한 일입니다.
  • 프로젝트가 클수록 더 많이 필요합니다 . 다시 말이됩니다. 정적 언어는 동적 언어에없는 견고성과 제어 기능을 제공합니다. 응용 프로그램이 더 크고 복잡할수록 (행동 적 측면에서) 필요한 제어 및 예측 가능성이 높아집니다.
  • 대규모 팀은 이미 정적 분석을 실행 하고 있습니다. 처음 두 점을 확인하는 것 같습니다.

이 작은 소개에 대한 마지막 참고 사항 : 이것은 선택적 기능이며, 내가 이해 한 바에 따르면 정적 입력의 이점을 얻기 위해 소개되었습니다.

일반적으로 걱정할 필요 가 없으며 확실히 사용할 필요가 없습니다 (특히 Python을 보조 스크립팅 언어로 사용하는 경우). 견고성, 제어력 및 추가 디버깅 기능을 많이 제공하므로 대규모 프로젝트를 개발할 때 도움이됩니다 .


mypy를 사용한 유형 힌트 :

이 답변을보다 완벽하게하기 위해 약간의 데모가 적합하다고 생각합니다. mypyType Hints가 PEP에 제시 될 때 영감을 얻은 라이브러리 인을 사용할 것 입니다. 이것은 주로이 질문에 부딪 히고 어디서부터 시작 해야할지 궁금한 사람을 위해 작성되었습니다.

그렇게하기 전에 다음을 반복 할 수 있습니다. PEP 484 는 아무 것도 시행하지 않습니다. 단순히 함수 주석의 방향을 설정하고 유형 검사 수행 방법에 대한 지침을 제안 합니다. 함수에 주석을 달고 원하는만큼 힌트를 줄 수 있습니다. 파이썬 자체는 주석을 사용하지 않기 때문에 주석의 존재 여부에 관계없이 스크립트는 계속 실행됩니다.

어쨌든 PEP에 명시된 바와 같이 힌트 유형은 일반적으로 세 가지 형식을 취해야합니다.

또한에 typing도입 된 새로운 모듈 과 함께 유형 힌트를 사용하려고합니다 Py3.5. 여기에는 정적 검사에 사용하기 위해 도우미 기능 및 데코레이터와 함께 많은 (추가) ABC (Abstract Base Classes)가 정의됩니다. 대부분 ABCscollections.abc포함되어 있지만에서 Generic순서 형태 (A 정의하여 가입을 허용하는 __getitem__()방법).

이것에 대한 더 자세한 설명에 관심이있는 사람 mypy documentation은 매우 훌륭하게 작성되었으며 검사기의 기능을 설명 / 설명하는 많은 코드 샘플이 있습니다. 확실히 읽을 가치가 있습니다.

함수 주석 및 특수 주석 :

첫째, 특별한 의견을 사용할 때 얻을 수있는 행동 중 일부를 관찰하는 것이 흥미 롭습니다. 특별한# type: type변수를 할당하는 동안 개체를 직접 추론 할 수없는 경우 개체 유형을 나타 내기 위해 메모를 추가 할 수 있습니다. 간단한 과제는 일반적으로 쉽게 추론되지만 목록과 같은 내용 (내용과 관련하여)은 할 수 없습니다.

참고 : 우리의 파생 제품을 사용하려는 경우 Containers우리는 그 컨테이너의 내용을 지정해야 합니다 사용 일반적인 으로부터 유형을 typing모듈. 이들은 인덱싱을 지원합니다.

# generic List, supports indexing.
from typing import List

# In this case, the type is easily inferred as type: int.
i = 0

# Even though the type can be inferred as of type list
# there is no way to know the contents of this list.
# By using type: List[str] we indicate we want to use a list of strings.
a = []  # type: List[str]

# Appending an int to our list
# is statically not correct.
a.append(i)

# Appending a string is fine.
a.append("i")

print(a)  # [0, 'i']

이러한 명령을 파일에 추가하고 인터프리터로 실행하면 모든 것이 제대로 작동하고 print(a)list의 내용을 인쇄합니다 a. # type의견은 폐기 된 추가 의미 론적 의미가없는 일반 주석으로 취급 .

mypy반면에 이것을 사용 하여 다음과 같은 응답을 얻습니다.

(Python3)jimmi@jim: mypy typeHintsCode.py
typesInline.py:14: error: Argument 1 to "append" of "list" has incompatible type "int"; expected "str"

str객체 목록에 int정적으로 말하는 소리를 포함 할 수 없음을 나타 냅니다. 이는 객체 의 유형을 a추가하고 추가하는 것만으로 str또는 내용의 유형을 변경하여 a값이 허용됨을 나타내도록 수정할 수 있습니다 ( 에서 가져온 List[Any]후 직관적으로 수행됨 ).Anytyping

함수 어노테이션은 param_name : type함수 시그니처의 각 매개 변수 뒤에 양식에 추가되며 리턴 함수 유형은 -> type종료 함수 콜론 앞의 표기법을 사용하여 지정됩니다 . 모든 주석은 __annotations__편리한 사전 양식으로 해당 기능 의 속성에 저장됩니다 . 간단한 예제 사용 ( typing모듈 에서 추가 유형이 필요하지 않음 ) :

def annotated(x: int, y: str) -> bool:
    return x < y

annotated.__annotations__속성은 이제 다음과 같은 값을가집니다 :

{'y': <class 'str'>, 'return': <class 'bool'>, 'x': <class 'int'>}

우리가 완전한 noobie이거나 Py2.7개념 에 익숙하고 결과적으로 TypeError비교에 숨어있는 것을 알지 못하면 annotated다른 정적 검사를 수행하고 오류를 포착하여 문제를 해결할 수 있습니다.

(Python3)jimmi@jim: mypy typeHintsCode.py
typeFunction.py: note: In function "annotated":
typeFunction.py:2: error: Unsupported operand types for > ("str" and "int")

무엇보다도 잘못된 인수로 함수를 호출하면 다음과 같은 결과가 나타납니다.

annotated(20, 20)

# mypy complains:
typeHintsCode.py:4: error: Argument 2 to "annotated" has incompatible type "int"; expected "str"

이것들은 기본적으로 모든 유스 케이스로 확장 될 수 있으며 잡힌 오류는 기본 호출 및 작업보다 더 확장됩니다. 확인할 수있는 유형은 실제로 유연하며 잠재력의 작은 몰래 피크를 제공했습니다. typing모듈, PEP 또는 mypy문서를 살펴보면 제공되는 기능에 대한보다 포괄적 인 아이디어를 얻을 수 있습니다.

스텁 파일 :

스텁 파일은 서로 다른 두 가지 비 독점적 인 경우에 사용할 수 있습니다.

  • 함수 서명을 직접 변경하지 않으려는 모듈을 유형 검사해야합니다.
  • 모듈을 작성하고 형식 검사를 원하지만 추가로 주석을 내용과 분리하려고합니다.

스텁 파일 (확장자 .pyi)은 사용하거나 사용하려는 모듈의 주석이 달린 인터페이스입니다. 여기에는 버린 함수 본문으로 유형을 검사하려는 함수의 서명이 포함됩니다. 다음과 같은 이름의 모듈에 세 개의 임의 함수 세트가 제공됩니다 randfunc.py.

def message(s):
    print(s)

def alterContents(myIterable):
    return [i for i in myIterable if i % 2 == 0]

def combine(messageFunc, itFunc):
    messageFunc("Printing the Iterable")
    a = alterContents(range(1, 20))
    return set(a)

스텁 파일을 만들 수 있으며 randfunc.pyi, 원하는 경우 제한을 둘 수 있습니다. 단점은 스텁없이 소스를 보는 사람이 실제로 전달되어야하는 것을 이해하려고 할 때 주석 지원을 실제로 얻지 못한다는 것입니다.

어쨌든, 스텁 파일의 구조는 매우 간단합니다. 모든 함수 정의를 빈 바디 ( pass채워진)로 추가하고 요구 사항에 따라 주석을 제공하십시오. 여기서는 int컨테이너의 유형으로 만 작업하고 싶다고 가정 해 봅시다 .

# Stub for randfucn.py
from typing import Iterable, List, Set, Callable

def message(s: str) -> None: pass

def alterContents(myIterable: Iterable[int])-> List[int]: pass

def combine(
    messageFunc: Callable[[str], Any],
    itFunc: Callable[[Iterable[int]], List[int]]
)-> Set[int]: pass

combine함수는 왜 다른 파일에서 주석을 사용하고 싶을지를 나타내며, 때로는 코드를 어지럽히고 가독성을 떨어 뜨립니다 (파이썬의 경우 큰 아니오). 물론 별칭을 사용할 수도 있지만 때로는 도움이되는 것보다 더 혼란 스럽습니다 (현명하게 사용하십시오).


이를 통해 파이썬에서 타입 힌트의 기본 개념을 익힐 수 있습니다. 사용 된 유형 검사기이지만 mypy점차적으로 더 많은 팝업을보아야합니다. 일부 내부에서는 IDE ( PyCharm ) 및 다른 일부는 표준 파이썬 모듈로 표시됩니다. 다음 목록에 추가 체커 / 관련 패키지를 추가하고 추가 할 때 (또는 제안 된 경우) 추가하려고합니다.

내가 아는 체커 :

  • Mypy : 여기에 설명 된대로.
  • PyType : Google은 내가 모은 것과는 다른 표기법을 사용합니다.

관련 패키지 / 프로젝트 :

  • typeshed : 표준 라이브러리에 대한 다양한 스터브 파일을 보관하는 공식 Python 저장소.

typeshed프로젝트는 실제로 자신의 프로젝트에서 유형 힌트를 사용하는 방법을 볼 수있는 가장 좋은 장소 중 하나입니다. 해당 파일 에서 클래스 __init__던전을Counter 예로 들어 보겠습니다 .pyi.

class Counter(Dict[_T, int], Generic[_T]):
        @overload
        def __init__(self) -> None: ...
        @overload
        def __init__(self, Mapping: Mapping[_T, int]) -> None: ...
        @overload
        def __init__(self, iterable: Iterable[_T]) -> None: ...

어디 _T = TypeVar('_T')일반적인 클래스를 정의하는 데 사용됩니다 . 를 들어 Counter클래스 우리는 하나, 그것의 초기화에 인수를 취하지 하나 얻을 수 있음을 알 수 Mapping에 모든 종류의를 int 또는 가지고 Iterable모든 종류의를.


주의 : 내가 언급 한 것을 잊어 버린 한 가지는 typing모듈이 잠정적으로 도입되었다는 것 입니다. 에서 PEP 411 :

임시 패키지는 "안정된"상태로 "졸업"하기 전에 API를 수정했을 수 있습니다. 한편으로,이 상태는 공식적으로 Python 배포판의 일부가되는 이점을 패키지에 제공합니다. 반면에 핵심 개발 팀은 패키지 API의 안정성과 관련하여 약속이 없으며 다음 릴리스에서 변경 될 수 있다고 명시 적으로 밝혔습니다. 예상치 못한 결과로 간주되지만 API 또는 유지 관리에 대한 우려가 입증 된 경우 이러한 패키지는 사용 중단 기간없이 표준 라이브러리에서 제거 될 수도 있습니다.

소금을 꼬집어 여기로 가져 가십시오. 나는 그것이 중요한 방법으로 제거되거나 변경 될 것이라고 의심하지만 아무도 알 수 없습니다.


** 타입 힌트의 범위에서 또 다른 전체 주제 만 유효합니다 : PEP 526: 구문 변수 주석을 대체하기위한 노력의 일환이다 # type사용자가 간단한 변수의 유형을 주석 할 수 있습니다 새로운 구문을 도입하여 의견을 varname: type진술.

Python 3.6의 변수 주석이란 무엇입니까?를 참조하십시오 . 앞에서 언급했듯이 이것에 대한 작은 소개가 필요합니다.


3
"파이썬의 매우 역동적 인 특성으로 인해 사용중인 객체의 유형을 유추하거나 확인하는 것이 특히 어렵습니다." 당신은 정적 검사를 참조하고 있습니까?
bsam

53

Jim의 정교한 답변에 추가 :

typing모듈 점검 –이 모듈은 PEP 484에 지정된 유형 힌트를 지원합니다 .

예를 들어 아래 함수는 type 값을 가져 와서 반환 str하며 다음과 같이 주석이 달립니다.

def greeting(name: str) -> str:
    return 'Hello ' + name

typing모듈은 또한 다음을 지원합니다.

  1. 별칭을 입력하십시오 .
  2. 콜백 함수에 대한 힌트 힌트 .
  3. 제네릭 -추상 기본 클래스가 컨테이너 요소의 예상 유형을 나타내도록 구독을 지원하도록 확장되었습니다.
  4. 사용자 정의 제네릭 형식 -사용자 정의 클래스는 제네릭 클래스로 정의 할 수 있습니다.
  5. 모든 유형 -모든 유형은 Any의 하위 유형입니다.

26

새로 출시 된 PyCharm 5는 유형 힌트를 지원합니다. 블로그 게시물 ( PyCharm 5의 Python 3.5 유형 힌트 참조 ) 에서 유형 힌트가 무엇인지 아닌지에 대한 훌륭한 설명을 제공합니다 코드에서이를 사용하는 방법에 대한 몇 가지 예제 및 삽화와 함께 제공 .

또한 이 주석 에서 설명하는 것처럼 Python 2.7에서 지원됩니다 .

PyCharm은 Python 2.7, Python 3.2-3.4 용 PyPI의 타이핑 모듈을 지원합니다. 2.7의 경우 함수 주석이 Python 3.0에서 추가되었으므로 * .pyi 스텁 파일에 유형 힌트를 입력해야합니다 .


0

유형 힌트는 최근 수십 년 동안 헝가리어처럼 단순한 이름 지정 규칙을 사용하지 않는 동적 언어에 최근 추가되었습니다 (첫 글자 b = 부울 리언, c = 문자, d = 사전, i = 정수, l = 목록, n = 숫자 인 객체 레이블 , s = string, t = tuple)은 너무 번거롭지 않았지만 이제는 오 기다려 ... 언어 (type ())을 사용하여 객체를 인식하고 멋진 IDE를 사용하는 것은 너무 많은 문제라고 결정했습니다. 복잡하고 역동적으로 할당 된 객체 값은 어쨌든 완전히 쓸모 없게 만드는 반면, 간단한 이름 지정 규칙은 모든 개발자를 위해 모든 것을 간단하게 해결할 수 있습니다.


솔직히 말하면, 이것은 대답보다 맹렬한 것처럼 들립니다.
Dimitris Fasarakis Hilliard

-1

타입 힌트는 유지 관리를위한 것이며 파이썬에 의해 해석되지 않습니다. 아래 코드에서 줄 def add(self, ic:int)은 다음 return...줄 까지 오류가 발생하지 않습니다 .

class C1:
    def __init__(self):
        self.idn = 1
    def add(self, ic: int):
        return self.idn + ic
    
c1 = C1()
c1.add(2)

c1.add(c1)
Traceback (most recent call last):
  File "<input>", line 1, in <module>
  File "<input>", line 5, in add
TypeError: unsupported operand type(s) for +: 'int' and 'C1'
 
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.