我如何指定方法的返回types与python中的类本身相同?
我在python 3中有以下代码:
class Position: def __init__(self, x: int, y: int): self.x = x self.y = y def __add__(self, other: Position) -> Position: return Position(self.x + other.x, self.y + other.y)
但是我的编辑(PyCharm)说参考位置不能被parsing(在_add__方法中)。 我应该如何指定我期望的返回types是Position
types?
编辑:我认为这实际上是一个PyCharm问题。 它实际上在其警告中使用了信息,并且代码完成
但是纠正我的错误,并且需要使用其他语法。
如果你尝试运行这个代码,你会得到:
NameError: name 'Position' is not defined
这是因为Position
必须先在注释中使用才能被定义。 如果您匆忙的“The Blessed Way”™是第二个,我将通过针对类似问题提出的解决方法。
1.定义一个虚拟的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
2.使用一个string
只需使用一个string,而不是类本身:
... def __add__(self, other: 'Position') -> 'Position': ...
如果您使用Django框架,这可能看起来很熟悉,因为Django模型使用string作为前向引用(外键模式为self
或尚未声明的外键定义)。
看起来这是根据文档推荐的方法:
转发引用
当一个types提示包含尚未定义的名称时,该定义可能被表示为一个string文字,稍后parsing。
发生这种情况通常是容器类的定义,其中定义的类出现在某些方法的签名中。 例如,以下代码(简单二叉树实现的开始)不起作用:
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
string文字应该包含一个有效的Pythonexpression式(也就是说,compile(lit,'','eval')应该是一个有效的代码对象),一旦模块完全加载,它应该没有错误地评估。 在其中进行评估的本地和全局名称空间应该是相同的名称空间,其中将评估对同一个函数的默认参数。
3.猴子补丁为了添加注释:
如果您使用强制执行合同的装饰器,则可以使用此方法:
... 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
至less看起来是对的:
>>> for k, v in Position.__add__.__annotations__.items(): ... print(k, 'is Position:', v is Position) return is Position: True other is Position: True
但是考虑一下,如果你足够聪明,可以编写一个合同执行装饰器,那么如果它是buitins.str
types而不是buitins.str
types的话,你可能会教它安全地eval
这个注释。
结论
祝福的方式是#2。
在parsing类体时,名字“位置”是不可取的。 我不知道你是如何使用types声明,而是Python的PEP 484 – 这是大多数模式应该使用的,如果使用这些types提示说你可以简单地把这个名字作为一个string在这个点上:
def __add__(self, other: 'Position') -> 'Position': return Position(self.x + other.x, self.y + other.y)
检查https://www.python.org/dev/peps/pep-0484/#forward-references – 符合的工具将知道从那里解开类名称并使用它(这总是很重要的记住,Python语言本身没有任何这些注释 – 它们通常用于静态代码分析,或者在运行时可以有用于types检查的库/框架 – 但是您必须明确地设置它们)