2

我并没有假装理解 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) 

会是什么?

4

1 回答 1

1

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

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

您可以使用模式compile或模式(模式通常用于语句和表达式)来解析这种类型的事物。ast.parse'func_type'execeval

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

# 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()))
于 2021-11-28T12:49:58.307 回答