IT story

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

hot-time 2020. 5. 6. 21:05
반응형

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


이야기의 기능에 대한 중 하나 Python 3.5되고이라고 type hints.

type hints기사이에 대한 예제가 언급되어 있으며, 유형 힌트를 책임감있게 사용하는 것에 대해서도 언급합니다. 누군가가 그것에 대해 그리고 언제 사용 해야하는지와 그렇지 않은지에 대해 더 자세히 설명 할 수 있습니까?


내가 읽고 제안 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']

If we add these commands to a file and execute them with our interpreter, everything works just fine and print(a) just prints the contents of list a. The # type comments have been discarded, treated as plain comments which have no additional semantic meaning.

By running this with mypy, on the other hand, we get the following responce:

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

Indicating that a list of str objects cannot contain an int, which, statically speaking, is sound. This can be fixed by either abiding to the type of a and only appending str objects or by changing the type of the contents of a to indicate that any value is acceptable (Intuitively performed with List[Any] after Any has been imported from typing).

Function annotations are added in the form param_name : type after each parameter in your function signature and a return type is specified using the -> type notation before the ending function colon; all annotations are stored in the __annotations__ attribute for that function in a handy dictionary form. Using a trivial example (which doesn't require extra types from the typing module):

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

The annotated.__annotations__ attribute now has the following values:

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

If we're a complete noobie, or we are familiar with Py2.7 concepts and are consequently unaware of the TypeError lurking in the comparison of annotated, we can perform another static check, catch the error and save us some trouble:

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

Among other things, calling the function with invalid arguments will also get caught:

annotated(20, 20)

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

These can be extended to basically any use-case and the errors caught extend further than basic calls and operations. The types you can check for are really flexible and I have merely given a small sneak peak of its potential. A look in the typing module, the PEPs or the mypy docs will give you a more comprehensive idea of the capabilities offered.

Stub Files:

Stub files can be used in two different non mutually exclusive cases:

  • You need to type check a module for which you do not want to directly alter the function signatures
  • You want to write modules and have type-checking but additionally want to separate annotations from content.

What stub files (with an extension of .pyi) are is an annotated interface of the module you are making/want to use. They contain the signatures of the functions you want to type-check with the body of the functions discarded. To get a feel of this, given a set of three random functions in a module named 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)

We can create a stub file randfunc.pyi, in which we can place some restrictions if we wish to do so. The downside is that somebody viewing the source without the stub won't really get that annotation assistance when trying to understand what is supposed to be passed where.

Anyway, the structure of a stub file is pretty simplistic: Add all function definitions with empty bodies (pass filled) and supply the annotations based on your requirements. Here, let's assume we only want to work with int types for our Containers.

# 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

The combine function gives an indication of why you might want to use annotations in a different file, they some times clutter up the code and reduce readability (big no-no for Python). You could of course use type aliases but that sometime confuses more than it helps (so use them wisely).


This should get you familiarized with the basic concepts of Type Hints in Python. Even though the type checker used has been mypy you should gradually start to see more of them pop-up, some internally in IDEs (PyCharm,) and others as standard python modules. I'll try and add additional checkers/related packages in the following list when and if I find them (or if suggested).

Checkers I know of:

  • Mypy: as described here.
  • PyType: By Google, uses different notation from what I gather, probably worth a look.

Related Packages/Projects:

  • typeshed: Official Python repo housing an assortment of stub files for the standard library.

The typeshed project is actually one of the best places you can look to see how type hinting might be used in a project of your own. Let's take as an example the __init__ dunders of the Counter class in the corresponding .pyi file:

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: ...

Where _T = TypeVar('_T') is used to define generic classes. For the Counter class we can see that it can either take no arguments in its initializer, get a single Mapping from any type to an int or take an Iterable of any type.


Notice: One thing I forgot to mention was that the typing module has been introduced on a provisional basis. From PEP 411:

A provisional package may have its API modified prior to "graduating" into a "stable" state. On one hand, this state provides the package with the benefits of being formally part of the Python distribution. On the other hand, the core development team explicitly states that no promises are made with regards to the the stability of the package's API, which may change for the next release. While it is considered an unlikely outcome, such packages may even be removed from the standard library without a deprecation period if the concerns regarding their API or maintenance prove well-founded.

So take things here with a pinch of salt; I'm doubtfull it will be removed or altered in significant ways but one can never know.


** Another topic altogether but valid in the scope of type-hints: PEP 526: Syntax for Variable Annotations is an effort to replace # type comments by introducing new syntax which allows users to annotate the type of variables in simple varname: type statements.

See What are variable annotations in Python 3.6?, as previously mentioned, for a small intro on these.


Adding to Jim's elaborate answer:

Check the typing module -- this module supports type hints as specified by PEP 484.

For example, the function below takes and returns values of type str and is annotated as follows:

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

The typing module also supports:

  1. Type aliasing.
  2. Type hinting for callback functions.
  3. Generics - Abstract base classes have been extended to support subscription to denote expected types for container elements.
  4. User-defined generic types - A user-defined class can be defined as a generic class.
  5. Any type - Every type is a subtype of Any.

The newly released PyCharm 5 supports type hinting. In their blog post about it (see Python 3.5 type hinting in PyCharm 5) they offer a great explanation of what type hints are and aren't along with several examples and illustrations for how to use them in your code.

Additionally, it is supported in Python 2.7, as explained in this comment:

PyCharm supports the typing module from PyPI for Python 2.7, Python 3.2-3.4. For 2.7 you have to put type hints in *.pyi stub files since function annotations were added in Python 3.0.

참고URL : https://stackoverflow.com/questions/32557920/what-are-type-hints-in-python-3-5

반응형