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

Ada*_*dam 19 python annotations type-hinting python-3.x

我打算使用Python函数注释来指定静态工厂方法的返回值的类型.我知道这是注释的理想用例之一.

class Trie:
    @staticmethod
    def from_mapping(mapping) -> Trie:
        # docstrings and initialization ommitted
        trie = Trie()
        return trie
Run Code Online (Sandbox Code Playgroud)

PEP 3107指出:

函数注释只不过是一种在编译时将任意Python表达式与函数的各个部分相关联的方法.

Trie是Python中的有效表达式,不是吗?Python不同意或者更确切地说,找不到名称:

def from_mapping(mapping) -> Trie:
NameError: name 'Trie' is not defined

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

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

小智 12

Trie是一个有效的表达式,并计算与名称关联的当前值Trie.但是该名称尚未定义 - 类对象仅在类主体运行到completition 绑定到其名称.在这个更简单的示例中,您将注意到相同的行为:

class C:
    myself = C
    # or even just
    C
Run Code Online (Sandbox Code Playgroud)

通常,解决方法是在类体之外定义类之后设置class属性.这不是一个非常好的选择,虽然它有效.或者,您可以在初始定义中使用任何占位符值,然后将其替换为__annotations__(这是合法的,因为它是常规字典):

class C:
    def f() -> ...: pass
print(C.f.__annotations__)
C.f.__annotations__['return'] = C
print(C.f.__annotations__)
Run Code Online (Sandbox Code Playgroud)

但它确实感觉相当hacky.根据您的使用情况,可能改为使用sentinel对象(例如CONTAINING_CLASS = object())并将其解释为实际处理注释的任何内容.

  • @codesparkle:解析与执行分开.执行时发生错误.您的类定义(包括注释)是代码的执行.但是,在定义类时,(显然)不执行函数的内部. (2认同)
  • @jamylak根据用例,这是可能的.然而,有许多用例不太有用甚至可怕(即任何人想要一个程序来确定你正在谈论的类型).老实说,对于那个文本描述,我只使用文档字符串. (2认同)

Hoc*_*key 11

PEP 484以前向参考的形式提供了正式的解决方案.

当类型提示包含尚未定义的名称时,该定义可以表示为字符串文字,稍后要解决.

在问题代码的情况下:

class Trie:
    @staticmethod
    def from_mapping(mapping) -> Trie:
        # docstrings and initialization ommitted
        trie = Trie()
        return trie
Run Code Online (Sandbox Code Playgroud)

变为:

class Trie:
    @staticmethod
    def from_mapping(mapping) -> 'Trie':
        # docstrings and initialization ommitted
        trie = Trie()
        return trie
Run Code Online (Sandbox Code Playgroud)