20. AST

Cây cú pháp trừu tượng, thường được gọi là AST, là cách biểu diễn có cấu trúc của mã nguồn Python sau khi phân tích cú pháp.

Trình mã thông báo tạo ra một dòng mã thông báo phẳng. Trình phân tích cú pháp nhận ra ngữ pháp. AST ghi lại kết quả dưới dạng cây câu lệnh và biểu thức.

Đối với nguồn này:python x = 1 + 2 AST có hình dạng như thế này:```text Module Assign targets: Name id="x", ctx=Store value: BinOp left: Constant value=1 op: Add right: Constant value=2


## 20.1 Vị trí trong Đường dẫn biên dịch

AST nm gia phân tích cú pháp và phân tích trình biên dch.```text
source bytes
    
tokenization
    
parsing
    
AST
    
AST validation
    
symbol table
    
compiler
    
code object
    
bytecode execution
```Trình phân tích cú pháp xây dng AST. Các giai đon sau tiêu th nó.

AST tr li các câu hi như:```text
What statements are in this module?
What expression is assigned to this name?
What is the body of this function?
What names are loaded, stored, or deleted?
What is the test expression of this if statement?
What is the element expression of this comprehension?
What source position produced this node?
```Nó không tr li nhng câu hi như:```text
Is this name local or global?
What bytecode should be emitted?
What stack size is needed?
What constants should be placed in co_consts?
What exception table entries are needed?
```Chúng thuc v các giai đon biên dch sau này.

## 20.2 Cây cú pháp cụ thể và Cây cú pháp trừu tượng

Trình phân tích cú pháp có th to ra cây cú pháp c th hoc cây cú pháp tru tượng.

Cây cú pháp c th bo tn chi tiết ng pháp. Nó đại din cht ch cho ngun.

Cây cú pháp tru tượng bo tn cu trúc ng nghĩa. Nó loi b các chi tiết mà giai đon biên dch sau này không cn.

Ví d:```python
x = (((1)))
```Cú pháp c th cha ba cp du ngoc đơn.

AST có th biu din điu này mt cách đơn gin như sau:```text
Assign
    target: Name "x"
    value: Constant 1
```Các du ngoc đơn nh hưởng đến vic phân tích cú pháp nhưng chúng không t to ra hành vi thi gian chy.

Tương t:```python
x = 1 + 2
```AST gi phn b sung vì nó nh hưởng đến hành vi thi gian chy.```text
BinOp
    left: Constant 1
    op: Add
    right: Constant 2
```Do đó, AST mang tính tru tượng theo nghĩa trình biên dch thc tế. Nó gi các hot động, không phi tt c chính t.

## 20.3 Truy cập AST cấp Python

Python th hin chc năng AST thông qua`ast`mô-đun.

Ví d:```python
import ast

tree = ast.parse("x = 1 + 2\n")
print(ast.dump(tree, indent=4))
```Đầu ra đin hình:```text
Module(
    body=[
        Assign(
            targets=[
                Name(id='x', ctx=Store())],
            value=BinOp(
                left=Constant(value=1),
                op=Add(),
                right=Constant(value=2)))],
    type_ignores=[])
```Đây là cu trúc chung mà CPython s dng ni b, được hin th dưới dng đối tượng Python.

các`ast`mô-đun hu ích cho:```text
static analysis
code generation
linting
refactoring
macro-like source transforms
security review tools
documentation tools
teaching compiler structure
```Nhưng API AST công khai vn còn là mt s tru tượng. Biu din C ni b ca CPython và các lp AST Python công khai có liên quan vi nhau, nhưng chúng không phi là cùng mt đối tượng vt lý.

## 20.4 Nút mô-đun

Thư mc gc ca mt tp Python bình thường là mt`Module`.

Ví d:```python
x = 1
print(x)
```Hình dng AST:```text
Module
    body:
        Assign
        Expr
    type_ignores:
        []
```các`body`là mt danh sách có th t các câu lnh.

 cp mô-đun, trình biên dch phát ra mã byte thc thi các câu lnh t trên xung dưới.

Có nhiu loi nút gc khác nhau tùy thuc vào chế độ phân tích cú pháp:

| Chế độ phân tích | Nút gc | Ví d |
| ------------------ | -------------- | -------------------- |
|`exec`             | `Module`       | `x = 1`              |
| `eval`             | `Expression`   | `1 + 2`              |
| `single`           | `Interactive`| Đầu vào REPL |
| chế độ loi chc năng |`FunctionType`| bình lun kiu kế tha |

Ví d:```python
import ast

print(type(ast.parse("x = 1", mode="exec")).__name__)
print(type(ast.parse("1 + 2", mode="eval")).__name__)
print(type(ast.parse("print(1)", mode="single")).__name__)
```Chế độ bt đầu ng pháp thay đổi hình dng AST gc.

## 20.5 Nút câu lệnh

Tuyên b th hin hành động.

Các nút câu lnh ph biến bao gm:

| Nút | Ví d ngun |
| ------------------ | ------------------------ |
|`Assign`           | `x = 1`                  |
| `AnnAssign`        | `x: int = 1`             |
| `AugAssign`        | `x += 1`                 |
| `Return`           | `return x`               |
| `If`               | `if x: ...`              |
| `For`              | `for x in xs: ...`       |
| `While`            | `while x: ...`           |
| `FunctionDef`      | `def f(): ...`           |
| `AsyncFunctionDef` | `async def f(): ...`     |
| `ClassDef`         | `class C: ...`           |
| `Try`              | `try: ... except: ...`   |
| `With`             | `with open(p) as f: ...` |
| `Import`           | `import os`              |
| `ImportFrom`       | `from os import path`    |
| `Expr`             | `f()`như mt li tuyên b |
|`Pass`             | `pass`                   |
| `Break`            | `break`                  |
| `Continue`         | `continue`               |
| `Raise`            | `raise ValueError()`     |
| `Assert`           | `assert x`               |
| `Delete`           | `del x`                  |
| `Global`           | `global x`               |
| `Nonlocal`         | `nonlocal x`|

Nút câu lnh xut hin  nơi ng pháp mong đợi mt câu lnh. Các nút câu lnh thường sng trong mt`body`, `orelse`, `finalbody`, hoc danh sách tương t.

Ví d:```python
if x:
    a = 1
else:
    a = 2
```Hình dng AST:```text
If
    test: Name "x", Load
    body:
        Assign a = 1
    orelse:
        Assign a = 2
```các`else`khi được đại din bi`orelse`cánh đồng.

## 20.6 Nút biểu thức

Biu thc to ra giá tr.

Các nút biu thc ph biến bao gm:

| Nút | Ví d ngun |
| -------------- | ------------------ |
|`Constant`     | `1`, `"x"`, `None` |
| `Name`         | `x`                |
| `BinOp`        | `a + b`            |
| `UnaryOp`      | `-x`               |
| `BoolOp`       | `a and b`          |
| `Compare`      | `a < b`            |
| `Call`         | `f(x)`             |
| `Attribute`    | `obj.name`         |
| `Subscript`    | `xs[i]`            |
| `List`         | `[1, 2]`           |
| `Tuple`        | `(1, 2)`           |
| `Dict`         | `{"a": 1}`         |
| `Set`          | `{1, 2}`           |
| `ListComp`     | `[x for x in xs]`  |
| `GeneratorExp` | `(x for x in xs)`  |
| `Lambda`       | `lambda x: x + 1`  |
| `IfExp`        | `a if cond else b` |
| `Yield`        | `yield x`          |
| `Await`        | `await task`       |
| `NamedExpr`    | `(x := f())`|

Ví d:```python
result = obj.method(x, y=2)
```Hình dng AST:```text
Assign
    target:
        Name "result", Store
    value:
        Call
            func:
                Attribute
                    value: Name "obj", Load
                    attr: "method"
                    ctx: Load
            args:
                Name "x", Load
            keywords:
                keyword arg="y", value=Constant 2
```AST ghi li mc tiêu cuc gi, đối s v trí, đối s t khóa và quyn truy cp thuc tính.

## 20.7 Ngữ cảnh biểu thức

Mt s nút biu thc mang ng cnh.

Các bi cnh quan trng nht là:

| Bi cnh | Ý nghĩa |
| ------- | -------------------------- |
|`Load`| Đọc mt giá tr |
|`Store`| Giao cho mt mc tiêu |
|`Del`| Xóa mt ràng buc hoc mc tiêu |

Ví d:```python
x = x + 1
```Hình dng AST:```text
Assign
    target:
        Name "x", Store
    value:
        BinOp
            left: Name "x", Load
            op: Add
            right: Constant 1
```Cách viết ging nhau,`x`, xut hin hai ln vi ý nghĩa khác nhau.

Ví d vi các thuc tính:```python
obj.value = obj.value + 1
```Hình dng AST:```text
Assign
    target:
        Attribute obj.value, Store
    value:
        BinOp
            left: Attribute obj.value, Load
            op: Add
            right: Constant 1
```Bi cnh là điu cn thiết để to mã. Vic ti tên, lưu tr tên và xóa tên s dng các hướng dn mã byte khác nhau.

## 20.8 Hằng số

S dng Python AST hin đại`Constant`cho nhiu giá tr nghĩa đen.

Ví d:```python
1
3.14
"hello"
b"bytes"
None
True
False
...
```Mi cái có th xut hin dưới dng:```text
Constant(value=...)
```Các ch cha là các nút riêng bit:```python
[1, 2]
(1, 2)
{"a": 1}
{1, 2}
```Hình dng AST:```text
List
    elts:
        Constant 1
        Constant 2

Tuple
    elts:
        Constant 1
        Constant 2

Dict
    keys:
        Constant "a"
    values:
        Constant 1

Set
    elts:
        Constant 1
        Constant 2
```Trình biên dch sau này có th gp mt s hng s. Ví d:```python
x = 1 + 2
```có th biên dch thành mt hng s`3`bng mã byte tùy thuc vào quy tc ti ưu hóa. Nhưng AST vn ghi li thao tác nh phân trước khi ti ưu hóa.

## 20.9 Toán tử đóng vai trò là Nút AST

Các toán t được biu din dưới dng các đối tượng nút AST nh.

Ví d:

| Ngun | Toán t AST |
| -------- | ------------ |
|`a + b`  | `Add`        |
| `a - b`  | `Sub`        |
| `a * b`  | `Mult`       |
| `a / b`  | `Div`        |
| `a // b` | `FloorDiv`   |
| `a % b`  | `Mod`        |
| `a ** b` | `Pow`        |
| `a @ b`  | `MatMult`    |
| `a << b` | `LShift`     |
| `a >> b` | `RShift`     |
| `a \| b` | `BitOr`      |
| `a & b`  | `BitAnd`     |
| `a ^ b`  | `BitXor`|

Ví d:```python
x = a + b
```AST:```text
BinOp
    left: Name "a"
    op: Add
    right: Name "b"
```Toán t không được lưu dưới dng chui. Nó được th hin mt cách có cu trúc.

Điu này làm cho mã trình biên dch xuôi dòng tr nên đơn gin hơn. Nó có th bt loi nút toán t thay vì phân tích li các toán t văn bn.

## 20.10 So sánh

Vic so sánh s dng hình dng AST đặc bit vì Python h tr so sánh theo chui.

Ví d:```python
a < b < c
```Điu này có nghĩa là:```python
a < b and b < c
```ngoi tr điu đó`b`được đánh giá mt ln.

Hình dng AST:```text
Compare
    left: Name "a"
    ops:
        Lt
        Lt
    comparators:
        Name "b"
        Name "c"
```Điu này khác vi các hot động nh phân.

Mt biu thc nh phân như:```python
a + b + c
```được lng nhau:```text
BinOp
    left:
        BinOp
            left: a
            op: Add
            right: b
    op: Add
    right: c
```Mt so sánh theo chui được biu din dưới dng mt`Compare`nút có nhiu toán t và b so sánh.

## 20.11 Các phép toán Boolean

Các phép toán Boolean cũng có hình dng AST riêng bit.

Ví d:```python
a and b and c
```Hình dng AST:```text
BoolOp
    op: And
    values:
        Name "a"
        Name "b"
        Name "c"
```Tương t:```python
a or b or c
```công dng`BoolOp`vi`Or`.

Hình dng này bo toàn cu trúc ngn mch. Trình biên dch phát ra mã byte để đánh giá các toán hng t trái sang phi và dng khi biết kết qu.

Các phép toán Boolean không phi là các lnh gi hàm thông thường. H có các quy tc đánh giá đặc bit.

## 20.12 Định nghĩa hàm

Mt định nghĩa hàm được biu din bi`FunctionDef`.

Ví d:```python
def add(a: int, b: int = 0) -> int:
    return a + b
```Hình dng AST:```text
FunctionDef
    name: "add"
    args:
        arguments
            args:
                arg "a", annotation: Name "int"
                arg "b", annotation: Name "int"
            defaults:
                Constant 0
    returns:
        Name "int"
    body:
        Return
            BinOp
                Name "a"
                Add
                Name "b"
    decorator_list:
        []
```Mt nút định nghĩa hàm lưu tr:```text
function name
argument structure
body statements
decorators
return annotation
type comment
source location
```Phn thân hàm không được thc thi trong khi phân tích cú pháp. Sau này nó s tr thành mt phn ca đối tượng mã ca hàm. Trong thi gian chy, vic thc thi`def`câu lnh to ra mt đối tượng hàm.

## 20.13 Đối số

Các đối s ca hàm được biu din bng mt`arguments`nút.

Nó phi h tr tt c các dng tham s Python:```python
def f(a, b=1, /, c=2, *args, d, e=3, **kwargs):
    pass
```AST phi phân bit:```text
positional-only parameters
positional-or-keyword parameters
varargs parameter
keyword-only parameters
keyword-only defaults
kwargs parameter
defaults
annotations
```Cu trúc này chi tiết hơn mt danh sách tên đơn gin.

Trình biên dch sau đó s dng nó để xây dng mt đối tượng mã vi s lượng đối s và c chính xác.

## 20.14 Định nghĩa lớp

Mt định nghĩa lp được biu din bi`ClassDef`.

Ví d:```python
class Point(Base):
    x = 0
    y = 0
```Hình dng AST:```text
ClassDef
    name: "Point"
    bases:
        Name "Base"
    keywords:
        []
    body:
        Assign x = 0
        Assign y = 0
    decorator_list:
        []
```Thân lp được biên dch thành mt khi thc thi. Trong thi gian chy, CPython thc thi phn thân lp để to ra mt không gian tên, sau đó gi b máy siêu d liu để to đối tượng lp.

AST ch ghi li cu trúc định nghĩa lp. Nó không xây dng lp hc.

## 20.15 Hiểu biết

S hiu biết có các nút AST chuyên dng.

Ví d:```python
[x for x in xs]
{x for x in xs}
{k: v for k, v in pairs}
(x for x in xs)
```Các loi nút AST:

| Mu ngun | Nút AST |
| -------------------- | -------------- |
| Danh sách hiu |`ListComp`|
| Đặt mc độ hiu |`SetComp`|
| Hiu chính t |`DictComp`|
| Biu thc máy phát đin |`GeneratorExp`|

Mi người s dng mt hoc nhiu`comprehension`nút.

Ví d:```python
[x * x for x in xs if x > 0]
```Hình dng AST:```text
ListComp
    elt:
        BinOp x * x
    generators:
        comprehension
            target: Name "x", Store
            iter: Name "xs", Load
            ifs:
                Compare x > 0
            is_async: 0
```S hiu biết là các nút biu thc, nhưng chúng đưa ra hành vi ràng buc cc b. Các giai đon biên dch sau này x lý phm vi ca chúng mt cách cn thn.

## 20.16 Khớp mẫu AST

So khp mu Python s dng các nút AST chuyên dng.

Ví d:```python
match value:
    case 0:
        result = "zero"
    case [x, y]:
        result = x + y
```Hình dng AST:```text
Match
    subject:
        Name "value"
    cases:
        match_case
            pattern: MatchValue Constant 0
            body:
                Assign result = "zero"
        match_case
            pattern: MatchSequence
                MatchAs name="x"
                MatchAs name="y"
            body:
                Assign result = x + y
```Các nút mu tách bit vi các nút biu thc vì cú pháp mu có ý nghĩa khác nhau.

Ví d:```python
case x:
```không ti mt biến có tên`x`. Nó ghi li mt giá tr vào tên`x`.

Đó là lý do ti sao vic khp mu không th s dng li các nút AST biu thc thông thường  mi nơi. Nó cn cu trúc theo mu c th.

## 20.17 Nút AST không đồng bộ

Cú pháp không đồng b cũng xut hin trong AST.

Ví d:```python
async def fetch():
    await client.get(url)
```Hình dng AST:```text
AsyncFunctionDef
    name: "fetch"
    body:
        Expr
            Await
                Call
                    Attribute client.get
```Các vòng lp và trình qun lý bi cnh không đồng b cũng có các biu mu chuyên dng:```python
async for item in stream:
    process(item)

async with lock:
    run()
```Các nút AST:```text
AsyncFor
AsyncWith
Await
AsyncFunctionDef
```Các nút này cho phép các giai đon biên dch sau này to ra mã byte nhn biết coroutine.

## 20.18 Vị trí nguồn

Các nút AST mang v trí ngun.

Các trường ph biến bao gm:```text
lineno
col_offset
end_lineno
end_col_offset
```Ví d:```python
import ast

tree = ast.parse("x = 1 + 2\n")
assign = tree.body[0]

print(assign.lineno)
print(assign.col_offset)
print(assign.end_lineno)
print(assign.end_col_offset)
```V trí ngun được s dng bi:```text
tracebacks
syntax errors
debuggers
profilers
coverage tools
AST transformers
editor tooling
```Khi to AST theo cách th công, vic thiếu v trí ngun có th gây ra li biên dch. Người tr giúp`ast.fix_missing_locations()`đin d liu v trí còn thiếu nếu có th.

Ví d:```python
import ast

tree = ast.Module(
    body=[
        ast.Assign(
            targets=[ast.Name(id="x", ctx=ast.Store())],
            value=ast.Constant(value=1),
        )
    ],
    type_ignores=[],
)

tree = ast.fix_missing_locations(tree)
code = compile(tree, "<ast>", "exec")
exec(code)
```## 20.19 Xác thực AST

Trước khi biên dch AST, CPython xác thc nó.

Xác thc bt nhng cây không đúng định dng như:```text
Name with no context
assignment target with Load context
expression where statement is required
statement where expression is required
invalid source location fields
invalid operator node placement
missing required fields
```Ví d v AST không hp l:```python
import ast

tree = ast.Module(
    body=[
        ast.Assign(
            targets=[ast.Name(id="x", ctx=ast.Load())],
            value=ast.Constant(value=1),
        )
    ],
    type_ignores=[],
)

tree = ast.fix_missing_locations(tree)
compile(tree, "<ast>", "exec")
```mc tiêu`x`có`Load`bi cnh, nhưng nhim v đòi hi`Store`. CPython bác b điu này.

Điu này quan trng bi vì công chúng`ast`module cho phép người dùng xây dng cây theo cách th công. Trình biên dch không được cho rng mi AST do người dùng to đều hp l.

## 20.20 Biến đổi AST

Công c AST có th sa đổi mã trước khi biên dch.

Ví d: thay thế mi hng s nguyên`1`vi`42`.

```python
import ast

class ReplaceOne(ast.NodeTransformer):
    def visit_Constant(self, node):
        if node.value == 1:
            return ast.copy_location(ast.Constant(value=42), node)
        return node

tree = ast.parse("x = 1\n")
tree = ReplaceOne().visit(tree)
tree = ast.fix_missing_locations(tree)

code = compile(tree, "<ast>", "exec")
ns = {}
exec(code, ns)

print(ns["x"])
```Bn in này:```text
42
```Chuyn đổi AST rt mnh m nhưng b hn chế. Cây được chuyn đổi vn phi tuân theo các quy tc hp l ca AST.

## 20.21 AST so với mã byte

AST và mã byte đại din cho các cp độ khác nhau.

Đối vi ngun này:```python
x = 1 + 2
```AST:```text
Assign
    Name "x", Store
    BinOp
        Constant 1
        Add
        Constant 2
```Mã byte có th trông ging như:```text
LOAD_CONST 3
STORE_NAME x
RETURN_CONST None
```Mã byte có th đã cha các hng s được ti ưu hóa. Nó cũng cha các hướng dn thc thi, không phi cú pháp ngun.

So sánh:

| Lp | Đại din | Bo qun |
| -------- | -------------------- | ------------------------------------------------- |
| Mã thông báo | Đơn v ngun t vng | chính t, nhn xét trong mã thông báo công khai, v trí |
| AST | Cu trúc cú pháp | câu nói, biu thc, bi cnh, v trí |
| Mã byte | Kế hoch thc hin | thao tác ngăn xếp, hng, tên, bước nhy |

AST gn ngun hơn mã byte nhưng kém chính xác hơn mã thông báo.

## 20.22 AST và bảng ký hiệu

Th bng ký hiu đọc AST để phân loi tên.

Ví d:```python
x = 1

def f():
    return x
```AST nói:```text
module assigns x
function f loads x
```Bng ký hiu quyết định:```text
x is global from inside f
f is local to module scope
```Ví d vi vic đóng ca:```python
def outer():
    x = 1

    def inner():
        return x

    return inner
```AST ghi li các hàm lng nhau và cách s dng tên. Bng ký hiu xác định rng:```text
x is local to outer
x is free in inner
x must be stored in a closure cell
```Đây không hoàn toàn là phân tích cú pháp. Nó yêu cu phân tích phm vi qua AST.

## 20.23 AST và tạo trình biên dịch

Trình biên dch x lý AST và phát ra mã byte.

Mô hình đơn gin hóa:```text
compile Module:
    compile each statement

compile Assign:
    compile right-hand expression
    compile each target in Store context

compile BinOp:
    compile left expression
    compile right expression
    emit binary operation instruction

compile If:
    compile test
    emit conditional jump
    compile body
    emit jump over else
    compile else body
```Trình biên dch là mt trình duyt dng cây vi logic điu khin lung và qun lý ngăn xếp.

Nó ph thuc vào cu trúc AST là chính xác. AST không đúng định dng có th gây ra mã byte sai, s c hoc trng thái thi gian chy không hp l, đó là lý do ti sao tn ti xác thc.

## 20.24 Tệp nguồn CPython AST

Các khu vc CPython quan trng bao gm:```text
Parser/Python.asdl
Python/Python-ast.c
Python/ast.c
Python/ast_opt.c
Python/symtable.c
Python/compile.c
Lib/ast.py
```Tp ASDL xác định lược đồ nút AST. Mã C được to cung cp các cu trúc và hàm to AST. Các nút xây dng mã AST và trình phân tích cú pháp t các kết qu khp ng pháp. Trình ti ưu hóa và trình biên dch s dng cây.

Vai trò khái nim:

| Khu vc | Vai trò |
| -------------- | ------------------------------------- |
| Lược đồ ASDL | Xác định các loi và trường nút AST |
| Hành động phân tích cú pháp | To nút AST t các kết qu khp ng pháp |
| Xác thc AST | T chi cây d hình |
| Trình ti ưu hóa AST | Thc hin đơn gin hóa cp cây |
| Bng ký hiu | Phân loi tên và phm vi |
| Trình biên dch | Phát ra mã byte t AST |
|`Lib/ast.py`| Người tr giúp AST cp Python |

## 20,25 Mô hình tinh thần tối thiểu

S dng mô hình này:```text
The AST is CPythons structured syntax tree.
It is built by the parser.
It removes most formatting details.
It records statements, expressions, operators, contexts, and source locations.
It separates syntax structure from later semantic analysis.
The symbol table pass reads the AST to classify names.
The compiler walks the AST to emit bytecode.
```AST là đối tượng chuyn giao trung tâm gia cú pháp và thc thi.