为什么包含类的名称不被识别为返回值函数注释?

时间:2013-04-01 10:40:13

标签: python python-3.x annotations type-hinting

我打算使用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

值得注意的是,如果指定了基本类型(例如objectint)或标准库类型(例如collections.deque),则不会发生此错误。

导致此错误的原因是什么?如何解决?

2 个答案:

答案 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