symtable —- 访问编译器的符号表

Source code: Lib/symtable.py [https://github.com/python/cpython/tree/3.13/Lib/symtable.py]


符号表由编译器在生成字节码之前根据 AST 生成。符号表负责计算代码中每个标识符的作用域。 symtable 提供了一个查看这些表的接口。

符号表的生成

  • symtable.symtable(code, filename, compile_type)
  • 返回 Python 源 代码 顶层的 SymbolTable。filename 是代码文件名。 compile_type 的含义类似 compile() 的 mode 参数。

符号表的查看

  • class symtable.SymbolTableType
  • 一个指明 SymbolTable 对象的类型的枚举。

    • MODULE = "module"
    • 用于模块的符号表。

    • FUNCTION = "function"

    • 用于函数的符号表。

    • CLASS = "class"

    • 用于类的符号表。

以下成员指向不同风格的 标注作用域

  • ANNOTATION = "annotation"
  • from __future__ import annotations 被激活时用于标注。

  • TYPE_ALIAS = "type alias"

  • 用于 type 构造的符号表。

  • TYPE_PARAMETERS = "type parameters"

  • 用于 泛型函数泛型类 的符号表。

  • TYPE_VARIABLE = "type variable"

  • 用于正式意义下的绑定、约束元组或单个类型变量的默认值的符号变量的符号表,即 TypeVar, TypeVarTuple 或 ParamSpec 对象(后两者不支持绑定或约束元组)。

Added in version 3.13.

  • class symtable.SymbolTable
  • 某个代码块的命名空间表。构造函数不公开。

    • get_type()
    • 返回符号表的类型。 可能的值为 SymbolTableType 枚举的成员。

在 3.12 版本发生变更: 增加 'annotation', 'TypeVar bound', 'type alias''type parameter' 作为可能的返回值。

在 3.13 版本发生变更: 返回值为 SymbolTableType 枚举的成员。

返回字符串的实际值可能在未来发生变化,因此,建议使用 SymbolTableType 成员而不是硬编码的字符串。

  • get_id()
  • 返回符号表的标识符

  • get_name()

  • 返回表名称。 如果表是针对类的则为类名;如果是针对函数的则为函数名;或者如果表是全局的 (get_type() 返回 'module') 则为 'top'。 对于类型形参作用域 (用于泛型类、函数和类型别名),它将为底层类、函数或类型别名的名称。 对于类型别名作用域,它将为类型别名的名称。 对于 TypeVar 绑定作用域,它将为 TypeVar 的名称。

  • get_lineno()

  • 返回符号表所代表代码块的第一行编号。

  • is_optimized()

  • 如果符号表中的局部变量可能被优化过,则返回 True

  • is_nested()

  • 如果代码块是嵌套类或函数,则返回 True

  • has_children()

  • 如果代码块中有嵌套的命名空间,则返回 True。可通过 get_children() 读取。

  • get_identifiers()

  • 返回一个包含表中符号名称的视图对象。 参见 视图对象文档

  • lookup(name)

  • 在符号表中查找 name 并返回一个 Symbol 实例。

  • get_symbols()

  • 返回符号表中所有符号的 Symbol 实例的列表。

  • get_children()

  • 返回嵌套符号表的列表。
  • class symtable.Function
  • 函数或方法的命名空间。 该类继承自 SymbolTable

    • get_parameters()
    • 返回由函数的参数名组成的元组。

    • get_locals()

    • 返回函数中局部变量名组成的元组。

    • get_globals()

    • 返回函数中全局变量名组成的元组。

    • get_nonlocals()

    • 返回一个包含在此函数中显式声明的非局部变量名称的元组。

    • get_frees()

    • 返回一个包含在此函数中的 自由(闭包)变量 名称的元组。
  • class symtable.Class
  • 类的命名空间。 该类继承自 SymbolTable

    • get_methods()
    • 返回一个包含类中声明的方法型函数的名称的元组。

在这里,术语 '方法' 是指 任何 在 class 语句体中通过 defasync def 定义的函数。

在更深的作用域(例如内部类)中定义的函数不会被 get_methods() 所获取。

例如:

  1. >>> import symtable
  2. >>> st = symtable.symtable('''
  3. ... def outer(): pass
  4. ...
  5. ... class A:
  6. ... def f():
  7. ... def w(): pass
  8. ...
  9. ... def g(self): pass
  10. ...
  11. ... @classmethod
  12. ... async def h(cls): pass
  13. ...
  14. ... global outer
  15. ... def outer(self): pass
  16. ... ''', 'test', 'exec')
  17. >>> class_A = st.get_children()[1]
  18. >>> class_A.get_methods()
  19. ('f', 'g', 'h')

虽然 A().f() 在运行时会引发 TypeError,但 A.f 仍然被视为是方法型函数。

  • class symtable.Symbol
  • SymbolTable 中的数据项,对应于源码中的某个标识符。构造函数不公开。

    • get_name()
    • 返回符号名

    • is_referenced()

    • 如果符号在代码块中被引用了,则返回 True

    • is_imported()

    • 如果符号是由导入语句创建的,则返回 True

    • is_parameter()

    • 如果符号是参数,返回 True

    • is_global()

    • 如果符号是全局变量,则返回 True

    • is_nonlocal()

    • 如果符号为非局部变量,则返回 True

    • is_declared_global()

    • 如果符号用 global 声明为全局变量,则返回 True

    • is_local()

    • 如果符号是代码块内的局部变量,则返回 True

    • is_annotated()

    • 如果符号带有注解,则返回 True

Added in version 3.6.

  • is_free()
  • 如果符号在代码块中被引用,但未赋值,则返回 True

  • is_assigned()

  • 如果符号在代码块中赋值,则返回 True

  • is_namespace()

  • 如果符号名绑定引入了新的命名空间,则返回 True

如果符号名用于函数或类定义语句,则为 True。

例如:

  1. >>> table = symtable.symtable("def some_func(): pass", "string", "exec")
  2. >>> table.lookup("some_func").is_namespace()
  3. True

注意,一个符号名可以与多个对象绑定。如果结果为 True,则该符号名还可以绑定到其他对象上,比如 int 或 list ,且不会引入新的命名空间。

  • get_namespaces()
  • 返回与符号名绑定的命名空间的列表。

  • get_namespace()

  • 返回绑定到这个名称的命名空间。 如果有多个命名空间或没有命名空间被绑定到这个名称,则会引发 ValueError

命令行用法

Added in version 3.13.

symtable 模块可以在命令行下作为脚本来执行。

  1. python -m symtable [infile...]

符号表将针对指定的 Python 文件生成并转储至 stdout。 如果未指定输入文件,将从 stdin 读取内容。