Python 표준 라 이브 러 리 의 typing 사용법(형식 표시)

PEP 3107 에는 기능 주석 문법 이,PEP 484 에는 유형 검사 가 추가 됐다
표준 라 이브 러 리 typing 은 형식 알림 이 지정 한 실행 시 지원 합 니 다.
예시:

def f(a: str, b:int) -> str:
    return a * b
在这里插入图片描述
실제 인삼 이 예상 한 유형 이 아니라면:
在这里插入图片描述
단,Python 이 실 행 될 때 함수 와 변수 형식 설명 을 강제 하지 않 습 니 다.유형 검사 기,IDE,lint 등 을 사용 해 야 코드 의 강제 유형 검 사 를 도 울 수 있 습 니 다.
NewType 생 성 형식 사용 하기
뉴 타 입()은 유형 검사 기 에 서로 다른 유형 을 표시 하 는 보조 함수 입 니 다.실행 할 때 함 수 를 되 돌려 줍 니 다.이 함 수 는 인 자 를 되 돌려 줍 니 다.

import typing
Id = typing.NewType("Id", int)
a = Id(2020)
뉴 타 입()을 사용 하여 만 든 형식 은 형식 검사 기 에 의 해 원본 형식의 하위 클래스 로 간 주 됩 니 다.
리 셋(Callable)
리 셋 함수 형식 을 Callable[[Arg1Type,Arg2type],ReturnType]으로 표시 합 니 다.

from typing import Callable
def f(a: int) -> str:
    return str(a)
def callback(a: int, func: Callable[[int], str]) -> str:
    return func(a)
print(callback(1, f))
범 형
용기 요소 에 예상 되 는 형식 을 추가 합 니 다.

from typing import Mapping
a: Mapping[str, str]
在这里插入图片描述
TypeVar 를 통 해 매개 변수 화 를 통 해 하나의 유형 집합 을 제약 합 니 다.

from typing import TypeVar
T = TypeVar('T') #        。
A = TypeVar('A', str, bytes) #     str   bytes
在这里插入图片描述
TypeVar 를 사용 하여 하나의 유형 집합 을 제약 하지만 하나의 제약 은 허용 되 지 않 습 니 다.
예 를 들 면:

T = TypeVar('T', str)
이렇게 하면 이상 한 타 입 오류 가 발생 합 니 다:single constraint is not allowed
typing 에 포 함 된 형식

AbstractSet = typing.AbstractSet
Any = typing.Any
AnyStr = ~AnyStr
AsyncContextManager = typing.AbstractAsyncContextManager
AsyncGenerator = typing.AsyncGenerator
AsyncIterable = typing.AsyncIterable
AsyncIterator = typing.AsyncIterator
Awaitable = typing.Awaitable
ByteString = typing.ByteString
Callable = typing.Callable
ClassVar = typing.ClassVar
Collection = typing.Collection
Container = typing.Container
ContextManager = typing.AbstractContextManager
Coroutine = typing.Coroutine
Counter = typing.Counter
DefaultDict = typing.DefaultDict
Deque = typing.Deque
Dict = typing.Dict
FrozenSet = typing.FrozenSet
Generator = typing.Generator
Hashable = typing.Hashable
ItemsView = typing.ItemsView
Iterable = typing.Iterable
Iterator = typing.Iterator
KeysView = typing.KeysView
List = typing.List
Mapping = typing.Mapping
MappingView = typing.MappingView
MutableMapping = typing.MutableMapping
MutableSequence = typing.MutableSequence
MutableSet = typing.MutableSet
NoReturn = typing.NoReturn
Optional = typing.Optional
Reversible = typing.Reversible
Sequence = typing.Sequence
Set = typing.Set
Sized = typing.Sized
TYPE_CHECKING = False
Tuple = typing.Tuple
Type = typing.Type
Union = typing.Union
ValuesView = typing.ValuesView
형식 주석 라 이브 러 리
간단 한 소개
동적 언어의 유연성 으로 인해 일부 도 구 를 만 들 고 스 크 립 트 를 만 들 때 매우 편리 하지만 대형 프로젝트 의 개발 에 도 문 제 를 가 져 왔 다.
python 3.5 부터 PEP 484 는 python 에 유형 주석(type hints)을 도 입 했 습 니 다.함수 주석(function annotation)의 문법 을 정 의 했 지만 의도 적 으로 정의 되 지 않 은 행 위 를 남 겼 습 니 다.현 재 는 정적 유형 에 대한 분석 을 위 한 제3자 도 구 를 많이 가지 고 있 습 니 다.pep 484 는 모듈 을 도입 하여 이 도 구 를 제공 합 니 다.주석(annoation)을 사용 할 수 없 는 경우 도 규정 하고 있다.

#           ,        
def greeting(name: str) -> str:
    return 'Hello ' + name
python 3.6 의 pep 526 에 따라 변수 유형 에 대한 성명 을 도 입 했 고 이전 에는 주석 에서 만 변수의 유형 에 대해 설명 할 수 있 었 습 니 다.

#            
primes = [] # type:list[int]
captain = ... #type:str
class Starship:
    stats = {} #type:Dict[str,int]
primes:List[int] = []
captain:str #Note: no initial value
class Starship:
    stats: ClassVar[Dict[str,int]] = {}
typing-type hints 지원 하 는 표준 라 이브 러 리
typing 모듈 은 표준 라 이브 러 리 의 provisional basis 에 추가 되 었 습 니 다.새로운 기능 이 증가 할 수 있 습 니 다.개발 자가 필요 하 다 고 생각 하면 api 도 달라 질 수 있 습 니 다.즉,뒤로 호환성 을 보장 하지 않 습 니 다.
우 리 는 이미 소개 에서 유형 주 해 를 소개 한 적 이 있 습 니 다.그러면 기본 유형의 int,str 를 제외 하고 유형 주 해 를 사용 하 는 유형 은 어떤 것 이 있 습 니까?
typing 라 이브 러 리 는 우리 가 유형 주 해 를 실현 하도록 도와 주 는 라 이브 러 리 입 니 다.
형식 별명(type alias)
아래 의 이 예 에서 Vector 와 List[float]는 동의어 로 볼 수 있다.

from typing import List
Vector = List[float]
def scale(scalar: float, vector: Vector)->Vector:
    return [scalar*num for num in vector]
new_vector = scale(2.0, [1.0, -4.2, 5.4])
유형 별명 은 복잡 한 유형 성명 을 간소화 하 는 데 도움 이 된다.

from typing import Dict, Tuple, List
ConnectionOptions = Dict[str, str]
Address = Tuple[str, int]
Server = Tuple[Address, ConnectionOptions]
def broadcast_message(message: str, servers: List[Server]) -> None:
    ...
# The static type checker will treat the previous type signature as
# being exactly equivalent to this one.
def broadcast_message(
        message: str,
        servers: List[Tuple[Tuple[str, int], Dict[str, str]]]) -> None:
    pass
새로운 유형(새로운 유형)
NewType 을 사용 하여 보조 함수 로 서로 다른 유형 을 만 듭 니 다.

form typing import NewType
UserId = NewType("UserId", int)
some_id = UserId(524313)
정적 형식 검사 기 는 새로운 형식 을 원본 형식의 하위 클래스 로 간주 합 니 다.이것 은 논리 적 오 류 를 포착 하 는 데 매우 유용 하 다.

def get_user_name(user_id: UserId) -> str:
    pass
# typechecks
user_a = get_user_name(UserId(42351))
# does not typecheck; an int is not a UserId
user_b = get_user_name(-1)
int 형식 변수의 모든 동작 을 사용 하여 UserId 형식의 변 수 를 사용 할 수 있 지만 결 과 는 int 형식 으로 되 돌아 갑 니 다.예컨대

# output   int     UserId  
output = UserId(23413) + UserId(54341)
UserId 형식 대신 int 형식 을 사용 하 는 것 을 막 을 수 는 없 지만 UserId 형식 을 남용 하 는 것 은 피 할 수 있 습 니 다.
이 검 사 는 정적 검사 기 에 의 해 강제 검 사 됩 니 다.실행 할 때 Derived=NewType('Derived',base)은 함수 하 나 를 파생 시 켜 전달 하 는 모든 인 자 를 되 돌려 줍 니 다.이것 은 Derived(some)를 의미 합 니 다.value)새 클래스 를 만 들 거나 일반 함수 호출 에 소모 되 는 함수 보다 소모 되 는 함 수 를 만 들 지 않 습 니 다.
정확히 말 하면 이 표현 식 somevalue is Derived(some_value)실행 할 때 항상 맞습니다.
이것 은 파생 된 하위 형식 을 만 들 수 없다 는 것 을 의미 합 니 다.실행 할 때 실제 형식 이 아니 라 표지 함수 이기 때 문 입 니 다.

from typing import NewType
UserId = NewType('UserId', int)
# Fails at runtime and does not typecheck
class AdminUserId(UserId): pass
그러나 파생 된 NewType 기반 의 새로운 형식 을 만 들 수 있 습 니 다.

from typing import NewType
UserId = NewType('UserId', int)
ProUserId = NewType('ProUserId', UserId)
그리고 ProUserId 의 유형 검 사 는 예상대로 작 동 합 니 다.
참고:유형 별 성명 을 사용 하 는 두 가지 유형 은 완전히 같 습 니 다.Doing=Original 은 정적 유형 을 검사 할 때 Alias 를 Original 과 동일시 합 니 다.이 결론 은 복잡 한 유형 성명 을 간소화 하 는 데 도움 이 됩 니 다.
Alias 와 달리 NewType 은 다른 하위 클래스 를 설명 합 니 다.Derived=NewType('Derived',Original)은 정적 형식 검 사 를 Original 의 하위 클래스 로 간주 합 니 다.이 는 형식 Original 이 형식 Derived 에 사용 할 수 없다 는 것 을 의미 합 니 다.논리 적 오 류 를 방지 하기 위해 최소 소 모 를 사용 하 는 데 도움 이 됩 니 다.
리 셋(callable)
리 셋 함 수 는 Callable[[[Arg1Type,Arg2type],ReturnType]과 같은 형식 주석 을 사용 할 수 있 습 니 다.
예컨대

from typing import Callable
def feeder(get_next_item: Callable[[], str]) -> None:
    # Body
def async_query(on_success: Callable[[int], None],
                on_error: Callable[[int, Exception], None]) -> None:
    # Body
형식 알림 의 매개 변수 목록 을 통 해 호출 가능 한 반환 형식 을 설명 할 수 있 습 니 다.예 를 들 어 Callable[...,ReturnType]과 같은 호출 매개 변 수 를 지정 하지 않 습 니 다.
범용(Generics)
용기 에 있 는 요소 의 유형 정 보 는 일반적인 방식 으로 정태 적 으로 추정 되 기 때문에 추상 류 는 용기 에 있 는 요 소 를 확대 하 는 데 사용 된다.

from typing import Mapping, Sequence
def notify_by_email(employees: Sequence[Employee],
                    overrides: Mapping[str, str]) -> None: ...
 
typing 의 TypeVar 를 통 해 일반적인 매개 변 수 를 화 할 수 있 습 니 다.

from typing import Sequence, TypeVar
T = TypeVar('T')      #       
def first(l: Sequence[T]) -> T:   # Generic function
    return l[0]
사용자 정의 일반 형식

from typing import TypeVar, Generic
from logging import Logger
T = TypeVar('T')
class LoggedVar(Generic[T]):
    def __init__(self, value: T, name: str, logger: Logger) -> None:
        self.name = name
        self.logger = logger
        self.value = value
    def set(self, new: T) -> None:
        self.log('Set ' + repr(self.value))
        self.value = new
    def get(self) -> T:
        self.log('Get ' + repr(self.value))
        return self.value
    def log(self, message: str) -> None:
        self.logger.info('%s: %s', self.name, message)
Generic[T]를 LoggedVar 의 기본 클래스 로 정의 하 는 동시에 T 도 방법 중의 매개 변수 로 사용 합 니 다.
Generic 기본 클래스 를 통 해 메타 클래스(metalass)정의 사용getitem__()LoggedVar[t]를 유효한 형식 으로 만 듭 니 다.

from typing import Iterable
def zero_all_vars(vars: Iterable[LoggedVar[int]]) -> None:
    for var in vars:
        var.set(0)
범 형 은 임의의 유형의 변수 일 수도 있 지만 제약 을 받 을 수도 있다.

from typing import TypeVar, Generic
...
T = TypeVar('T')
S = TypeVar('S', int, str)
class StrangePair(Generic[T, S]):
    ...
각 유형의 변수의 매개 변 수 는 반드시 다 르 게 해 야 한다.
다음은 불법 입 니 다.

from typing import TypeVar, Generic
...
T = TypeVar('T')
class Pair(Generic[T, T]):   # INVALID
    ...
제 네 릭 을 사용 하여 다 중 계승 을 실현 할 수 있 습 니 다.

from typing import TypeVar, Generic, Sized
T = TypeVar('T')
class LinkedList(Sized, Generic[T]):
    ... 
일반적인 유형 을 계승 할 때 일부 유형 변 수 는 고정 시 킬 수 있다.

from typing import TypeVar, Mapping
T = TypeVar('T')
class MyDict(Mapping[str, T]):
    ...
유형 매개 변 수 를 지정 하지 않 고 일반 클래스 를 사용 하면 모든 위치 가 Any 라 고 가정 합 니 다.아래 의 예 에서 my iterable 은 범 형 이 아니 지만 암시 적 계승 Iterable[Any]

from typing import Iterable
class MyIterable(Iterable): # Same as Iterable[Any]
사용자 가 정의 하 는 일반적인 형식 별명 도 지원 합 니 다.실례:

from typing import TypeVar, Iterable, Tuple, Union
S = TypeVar('S')
Response = Union[Iterable[S], int]
# Return type here is same as Union[Iterable[str], int]
def response(query: str) -> Response[str]:
    ...
T = TypeVar('T', int, float, complex)
Vec = Iterable[Tuple[T, T]]
def inproduct(v: Vec[T]) -> T: # Same as Iterable[Tuple[T, T]]
    return sum(x*y for x, y in v)
Generic 의 원 류 는 abc.ABCMeta 의 하위 클래스 이 고,범 형 류 는 추상 적 인 방법 이나 속성 을 포함 하 는 ABC 클래스 일 수 있 습 니 다(A generic class can be an ABC by including abstract methods or properties)
또한 범 형 류 는 원류 충돌 없 이 ABC 류 의 방법 을 포함 할 수 있다.
Any
특수 한 유형 은정적 형식 검사 기 는 모든 유형 을 모든 유형 과 호 환 되 고 모든 유형 과 호 환 되 는 것 으로 간주 합 니 다.

from typing import Any
a = None    # type: Any
a = []      # OK
a = 2       # OK
s = ''      # type: str
s = a       # OK
def foo(item: Any) -> int:
    # Typechecks; 'item' could be any type,
    # and that type might have a 'bar' method
    item.bar()
    ...
이상 은 개인 적 인 경험 이 므 로 여러분 에 게 참고 가 되 기 를 바 랍 니 다.여러분 들 도 저 희 를 많이 응원 해 주시 기 바 랍 니 다.

좋은 웹페이지 즐겨찾기