TL; DR : Python 4.0을 사용하는 경우 작동합니다. 3.7 이상에서 오늘 (2019)부터 미래 진술 ( from __future__ import annotations
) 을 사용 하여이 기능을 켜야합니다 .Python 3.6 이하에서는 문자열을 사용하십시오.
이 예외가 있다고 생각합니다.
NameError: name 'Position' is not defined
Position
파이썬 4를 사용하지 않는 한 주석에 사용하려면 먼저 정의해야 하기 때문 입니다.
파이썬 3.7 이상 : from __future__ import annotations
Python 3.7은 PEP 563 : 연기 된 주석 평가를 도입했습니다 . future 문을 사용하는 모듈은 from __future__ import annotations
주석을 문자열로 자동 저장합니다.
from __future__ import annotations
class Position:
def __add__(self, other: Position) -> Position:
...
이것은 Python 4.0에서 기본값이 될 예정입니다. 파이썬은 여전히 동적으로 유형이 지정된 언어이므로 런타임에 유형 검사가 수행되지 않으므로 주석을 입력해도 성능에 영향을 미치지 않아야합니다. 잘못된! 파이썬 3.7로 사용되는 입력 모듈 전에 코어에서 가장 느린 파이썬 모듈 중 하나 그래서 당신이 만약 import typing
당신이 볼 시간이 성능 증가 7까지 당신이 3.7로 업그레이드 할 때.
파이썬 <3.7 : 문자열 사용
PEP 484에 따르면 클래스 자체 대신 문자열을 사용해야합니다.
class Position:
...
def __add__(self, other: 'Position') -> 'Position':
...
Django 프레임 워크를 사용하는 경우 Django 모델도 순방향 참조를 위해 문자열을 사용하므로 친숙 할 수 있습니다 (외래 모델이 self
아직 선언되지 않았거나 아직 선언되지 않은 외국 키 정의 ). 이것은 Pycharm 및 기타 도구와 함께 작동해야합니다.
출처
여행을 절약하기 위해 PEP 484 및 PEP 563 의 관련 부품 :
앞으로 참조
형식 힌트에 아직 정의되지 않은 이름이 포함 된 경우 해당 정의는 문자열 리터럴로 표현되어 나중에 확인할 수 있습니다.
이것이 일반적으로 발생하는 상황은 정의 된 클래스가 일부 메소드의 서명에서 발생하는 컨테이너 클래스의 정의입니다. 예를 들어 다음 코드 (간단한 이진 트리 구현 시작)는 작동하지 않습니다.
class Tree:
def __init__(self, left: Tree, right: Tree):
self.left = left
self.right = right
이를 해결하기 위해 다음과 같이 씁니다.
class Tree:
def __init__(self, left: 'Tree', right: 'Tree'):
self.left = left
self.right = right
문자열 리터럴에는 유효한 Python 표현식 (예 : compile (lit, '', 'eval')은 유효한 코드 객체 여야 함)이 포함되어야하며 모듈이 완전히로드되면 오류없이 평가해야합니다. 평가되는 로컬 및 글로벌 네임 스페이스는 동일한 함수에 대한 기본 인수가 평가되는 동일한 네임 스페이스 여야합니다.
및 PEP 563 :
Python 4.0에서는 정의시 함수 및 변수 주석이 더 이상 평가되지 않습니다. 대신 문자열 형식이 각 __annotations__
사전에 유지됩니다 . 정적 형식 검사기는 동작에 차이가없는 반면 런타임에 주석을 사용하는 도구는 연기 된 평가를 수행해야합니다.
...
위에서 설명한 기능은 다음 특수 가져 오기를 사용하여 Python 3.7부터 사용할 수 있습니다.
from __future__ import annotations
대신 유혹을받을 수있는 것들
A. 더미 정의 Position
클래스 정의 전에 더미 정의를 배치하십시오.
class Position(object):
pass
class Position(object):
...
이것은 제거 NameError
되고 OK처럼 보일 수도 있습니다.
>>> Position.__add__.__annotations__
{'other': __main__.Position, 'return': __main__.Position}
하지만 그렇습니까?
>>> for k, v in Position.__add__.__annotations__.items():
... print(k, 'is Position:', v is Position)
return is Position: False
other is Position: False
B. 주석을 추가하기위한 Monkey-patch :
주석을 추가하기 위해 파이썬 메타 프로그래밍 마술을 시도하고 클래스 정의를 원숭이 패치하기 위해 데코레이터를 작성할 수 있습니다.
class Position:
...
def __add__(self, other):
return self.__class__(self.x + other.x, self.y + other.y)
데코레이터는 이에 상응하는 책임이 있습니다.
Position.__add__.__annotations__['return'] = Position
Position.__add__.__annotations__['other'] = Position
적어도 옳은 것 같습니다.
>>> for k, v in Position.__add__.__annotations__.items():
... print(k, 'is Position:', v is Position)
return is Position: True
other is Position: True
아마 너무 많은 문제입니다.
결론
3.6 이하를 사용하는 경우 클래스 이름을 포함하는 문자열 리터럴을 3.7에서 사용 from __future__ import annotations
하면 작동합니다.