Python: python ast 中的 ast.FunctionType 是什么?

Python: what is the ast.FunctionType in python ast?

我不假装理解了 python ast 中的所有内容,但是 FunctionType 是困扰我的东西。

mod = Module(stmt* body, type_ignore *type_ignores)
        | Interactive(stmt* body)
        | Expression(expr body)
        | FunctionType(expr* argtypes, expr returns)
        | Suite(stmt* body) 

它可以是什么?

FunctionType 是顶级符号 returned 用于解析函数类型的 # type: (args) -> return_type 注释(由 PEP484 指定)

我能找到的唯一权威来源是 Python 3.8 的更新日志,其中添加了它:https://docs.python.org/3/whatsnew/3.8.html#ast

您可以使用 compileast.parse'func_type' 模式解析此类内容(其中模式通常是 exec 语句和 eval 用于表达式)。

这仅在您尝试使用 Python 2 语法注释函数 return 类型时(由外部类型检查软件使用)使用,例如:

# Invalid syntax in Python 2
# def f(x: int, y: int) -> int:
#     return x * y

# Special type of type hint for functions in Python 2  (and also works in Python 3)
def f(x, y):
    # type: (int, int) -> int
    return x * y

# Or alternative syntax:
def f(
    x,  # type: int
    y   # type: int
):
    # type: (...) -> int
    return x * y

普通类型注解只能在'eval'模式下解析,但函数类型注解不能,所以添加了新模式和顶级符号:

https://github.com/python/cpython/blob/main/Grammar/python.gram#L91

func_type[mod_ty]: '(' a=[type_expressions] ')' '->' b=expression NEWLINE* ENDMARKER { _PyAST_FunctionType(a, b, p->arena) }

类型检查器可以使用它来解析这些类型的注释:

import ast

source = '''
def f(x, y):
    # type: (int, int) -> int
    return x * y
'''

module = ast.parse(source, mode='exec', type_comments=True)

class PrintFunctionTypes(ast.NodeVisitor):
    def visit_FunctionDef(self, f):
        print('FunctionDef:\n' + ast.dump(f))
        print('\ntype_comment:\n' + f.type_comment)
        parsed_comment = ast.parse(f.type_comment, mode='func_type')
        print('\nWhen parsed:\n' + ast.dump(parsed_comment))

PrintFunctionTypes().visit(module)

输出:

FunctionDef:
FunctionDef(name='f', args=arguments(posonlyargs=[], args=[arg(arg='x'), arg(arg='y')], kwonlyargs=[], kw_defaults=[], defaults=[]), body=[Return(value=BinOp(left=Name(id='x', ctx=Load()), op=Mult(), right=Name(id='y', ctx=Load())))], decorator_list=[], type_comment='(int, int) -> int')

type_comment:
(int, int) -> int

When parsed:
FunctionType(argtypes=[Name(id='int', ctx=Load()), Name(id='int', ctx=Load())], returns=Name(id='int', ctx=Load()))