TL;DR:截至今天(2019年),在Python 3.7+中,您可以使用“future”语句从__future__导入注释开启此功能。
(由__future__导入注释启用的行为可能成为Python未来版本的默认值,并将在Python 3.10中成为默认值。然而,3.10的改动在最后一刻被恢复了,现在可能根本不会发生了。)
在Python 3.6或以下版本中,应该使用字符串。
我猜你得到了这个例外:
NameError: name 'Position' is not defined
这是因为必须先定义Position,然后才能在注释中使用它,除非您使用的Python启用了PEP 563更改。
Python 3.7+:从__future__导入注释
Python 3.7引入了PEP 563:注释的延迟求值。使用__future__ import注释中的future语句的模块将自动将注释存储为字符串:
from __future__ import annotations
class Position:
def __add__(self, other: Position) -> Position:
...
这已被安排成为Python 3.10的默认值,但这一更改现在已被推迟。由于Python仍然是一种动态类型语言,因此在运行时不进行类型检查,因此键入注释应该不会对性能产生影响,对吗?错了!在Python 3.7之前,类型模块曾经是核心中最慢的Python模块之一,因此对于涉及导入类型模块的代码,当您升级到3.7时,性能将提高7倍。
Python <3.7:使用字符串
根据PEP 484,您应该使用字符串而不是类本身:
class Position:
...
def __add__(self, other: 'Position') -> 'Position':
...
如果你使用Django框架,这可能很熟悉,因为Django模型也使用字符串进行前向引用(外部模型是self或尚未声明的外键定义)。这应该与Pycharm和其他工具一起工作。
来源
PEP 484和PEP 563的相关部分,以避免您的旅程:
Forward references
When a type hint contains names that have not been defined yet, that definition may be expressed as a string literal, to be resolved later.
A situation where this occurs commonly is the definition of a container class, where the class being defined occurs in the signature of some of the methods. For example, the following code (the start of a simple binary tree implementation) does not work:
class Tree:
def __init__(self, left: Tree, right: Tree):
self.left = left
self.right = right
To address this, we write:
class Tree:
def __init__(self, left: 'Tree', right: 'Tree'):
self.left = left
self.right = right
The string literal should contain a valid Python expression (i.e., compile(lit, '', 'eval') should be a valid code object) and it should evaluate without errors once the module has been fully loaded. The local and global namespace in which it is evaluated should be the same namespaces in which default arguments to the same function would be evaluated.
PEP 563:
Implementation
In Python 3.10, function and variable annotations will no longer be evaluated at definition time. Instead, a string form will be preserved in the respective __annotations__ dictionary. Static type checkers will see no difference in behavior, whereas tools using annotations at runtime will have to perform postponed evaluation.
...
Enabling the future behavior in Python 3.7
The functionality described above can be enabled starting from Python 3.7 using the following special import:
from __future__ import annotations
你可能会被诱惑去做的事情
a .定义一个虚拟位置
在类定义之前,放置一个虚拟定义:
class Position(object):
pass
class Position(object):
...
这将消除NameError,甚至看起来还可以:
>>> 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:
您可能想尝试一些Python元编程魔法并编写一个装饰器
修补类定义以添加注释:
class Position:
...
def __add__(self, other):
return self.__class__(self.x + other.x, self.y + other.y)
decorator应该负责如下内容:
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
可能太麻烦了。