我打算使用Python function annotations来指定静态工厂方法的返回值的类型。我理解这是one of the desired use cases注释。
class Trie:
@staticmethod
def from_mapping(mapping) -> Trie:
# docstrings and initialization ommitted
trie = Trie()
return trie
PEP 3107声明:
函数注释只不过是一种在编译时将任意Python表达式与函数的各个部分相关联的方法。
Trie
是Python中的有效表达式,不是吗? Python不同意或者更确切地说,找不到名称:
def from_mapping(mapping) -> Trie:
NameError: name 'Trie' is not defined
值得注意的是,如果指定了基本类型(例如object
或int
)或标准库类型(例如collections.deque
),则不会发生此错误。
导致此错误的原因是什么?如何解决?
答案 0 :(得分:12)
Trie
是一个有效的表达式,并计算与名称Trie
关联的当前值。但是,该名称尚未定义 - 在类主体运行到completition之后,类对象仅绑定到其名称。在这个更简单的例子中你会注意到相同的行为:
class C:
myself = C
# or even just
C
通常,解决方法是在类体之外定义类之后设置class属性。这不是一个非常好的选择,虽然它有效。或者,您可以在初始定义中使用任何占位符值,然后在__annotations__
中替换它(这是合法的,因为它是常规字典):
class C:
def f() -> ...: pass
print(C.f.__annotations__)
C.f.__annotations__['return'] = C
print(C.f.__annotations__)
确实感到相当hacky。根据您的使用情况,可以改为使用sentinel对象(例如CONTAINING_CLASS = object()
)并将其解释为实际处理注释的任何内容。
答案 1 :(得分:11)
PEP 484以forward references的形式提供了正式的解决方案。
当类型提示包含尚未定义的名称时,该定义可以表示为字符串文字,稍后要解决。
如果是问题代码:
class Trie:
@staticmethod
def from_mapping(mapping) -> Trie:
# docstrings and initialization ommitted
trie = Trie()
return trie
变为:
class Trie:
@staticmethod
def from_mapping(mapping) -> 'Trie':
# docstrings and initialization ommitted
trie = Trie()
return trie