from enum import Enum
class TokenType(Enum):
pass
class Token:
pass模块化
约 799 字大约 3 分钟
2026-01-03
现在我们已经有一个项目了。它除了能够 print 一个字符串之外什么都不会。这章结束,它仍然什么都不会。但是我们将所有的模块准备好,这就好比一个楼房的骨架。我们将在后面的章节中逐步完善它。仍然要再次强调,真实的项目中模块的设置和细分是需要有很多权衡的。这里我们把模块先创建好,是为了让这个项目有一个有限的目标,看起来不太难。
回顾一下我们之前的模块。其中token和ast是数据模块。其他的模块都是功能模块。
- token
- ast
- lexer
- parser
- evaluator
- repl
在 Python 中,每个模块都是一个独立的文件。每个模块都有自己的命名空间,模块中的变量、函数、类等都只能在该模块中访问。如果要在别的模块中使用该模块中的变量、函数、类等,需要使用import语句导入该模块。
如果你仍然在项目根目录下,那么执行以下命令应该看到__init__.py文件。
$ ls src/pyec
__init__.py现在我们创建全部的模块文件。
$ touch src/pyec/token.py
$ touch src/pyec/ast.py
$ touch src/pyec/lexer.py
$ touch src/pyec/parser.py
$ touch src/pyec/evaluator.py
$ touch src/pyec/repl.py
$ ls src/pyec
ast.py evaluator.py __init__.py lexer.py parser.py repl.py token.py光从创建文件当然还没有结束,我们也来添加一些框架代码。这也是为后面实现做的一些预告。让我们把目光再次放到开头的流程图上。
先看平行四边形的数据节点。
源代码经过词法分析得到一列的 token。于是,token.py模块就会有一个叫做Token的类。其次,token 是由多个类型的,譬如整数,或者加号。于是我们还需要TokenType这个枚举类。
类似地,ast.py模块中应当包含语法分析器所产生的抽象语法树。在研究计算机程序结构的时候,我们将语法分析器的产物归纳为表达式、语句、函数和程序。在我们这个小项目中,语句和函数都是大材小用了。于是我们只需要Expression和Program这两个类。
class Expression:
pass
class Program:
pass对于lexer.py、parser.py和evaluator.py这三个模块,我们目前的处理就是添加Lexer、Parser和Evaluator这三个类。
class Lexer:
passclass Parser:
passclass Evaluator:
pass还剩下repl.py模块。作为这章的结束,我们还是想做一些更有用的事情。我们在repl.py模块中添加一个start()函数。让__init__.py中的main()函数调用它。要使用repl.py模块,需要用import语句先导入它。下面是两个文件的内容。
def start() -> None:
passfrom pyec import repl
def main() -> None:
print("Hello from pyec!")
repl.start()修改完毕之后,我们可以用uv run pyec来运行项目。它会打印出Hello from pyec!。这个结果和之前是一样的。
不要忘了,要把改动提交到 Git 仓库。
$ git add .
$ git commit -m "modularize the project"