#21. Bảng ký hiệu

Sau khi phân tích cú pháp tạo ra AST, CPython thực hiện phân tích phạm vi.

Giai đoạn này xây dựng các bảng ký hiệu.

Bảng ký hiệu ghi lại cách hoạt động của tên trong từng phạm vi. Nó xác định xem tên là cục bộ, toàn cầu, miễn phí, ô, tham số, được nhập, chú thích hay được tham chiếu từ phạm vi lồng nhau.

Đối với nguồn này:```python x = 10

def outer(): y = 20

def inner():
    return x + y

return inner

Giai đoạn bảng ký hiệu xác định:```text
x       global from inner
y       free variable in inner
y       cell variable in outer
inner   local variable in outer
outer   global variable in module
```Phân tích này rất cần thiết vì việc tạo mã byte phụ thuộc vào nó. Việc tải một biến cục bộ sử dụng mã byte khác với việc tải một biến toàn cục hoặc biến đóng.

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

Giai đoạn bảng ký hiệu nằm giữa quá trình xây dựng AST và tạo mã byte.```text
source
tokenization
parsing
AST
symbol table analysis
compiler
code object
bytecode execution
```Trình phân tích cú pháp xây dựng cấu trúc cú pháp.

Giai đoạn bảng ký hiệu xây dựng cấu trúc phạm vi.

Trình biên dịch sau đó sử dụng cả hai.

## 21.2 Bảng ký hiệu chứa đựng những gì

Mỗi phạm vi có một bảng ký hiệu.

Bảng ký hiệu lưu trữ các thông tin như:```text
which names exist
where names are assigned
where names are read
whether names are parameters
whether names are imported
whether names are global
whether names are nonlocal
whether names escape into nested scopes
whether names require closure cells
```Về mặt khái niệm:```text
Scope: function outer

Symbols:
    y       local + cell
    inner   local
Scope: function inner

Symbols:
    x       global
    y       free
```Giai đoạn bảng ký hiệu không thực thi mã. Nó thực hiện phân loại phạm vi tĩnh.

## 21.3 Python sử dụng phạm vi từ vựng

Python sử dụng phạm vi từ vựng.

Hàm lồng nhau có thể truy cập tên từ phạm vi kèm theo.

Ví dụ:```python
def outer():
    x = 10

    def inner():
        return x

    return inner

innercó thể truy cậpxbởi vìxtồn tại trong môi trường từ vựng bao quanh.

Giai đoạn bảng ký hiệu xác định mối quan hệ này trước khi thực thi thời gian chạy.

Nếu không phân tích phạm vi từ vựng, CPython sẽ không biết:```text where to look for a name whether to allocate closure storage whether a name belongs in locals whether a variable escapes into nested functions


Python có mt s loi phm vi.

| Phm vi | Ví d |
| ------------------- | ----------------- |
| Phm vi mô-đun | tp tin cp cao nht |
| Phm vi chc năng |`def f():`|
| Phm vi lp hc |`class C:`|
| Phm vi hiu |`[x for x in xs]`|
| Phm vi máy phát đin |`(x for x in xs)`|
| Phm vi Lambda |`lambda x: x + 1`|

Mi phm vi có phân tích biu tượng độc lp.

Ví d:```python
x = 1

def f():
    x = 2
    return x
```Mi mô-đun và chc năng đều có cái riêng`x`.

Giai đon bng biu tượng ngăn cách chúng.

## 21.5 Phạm vi mô-đun

Mã cp cao nht thc thi trong phm vi mô-đun.

Ví d:```python
x = 1
y = 2

def add():
    return x + y
``` phm vi mô-đun:```text
x       global/module-local
y       global/module-local
add     global/module-local
```Bên trong`add`:

```text
x       global
y       global
```Trong thi gian chy, toàn cu được lưu tr trong t đin mô-đun.

Giai đon bng ký hiu xác định rng các tham chiếu bên trong`add`nên s dng mã byte tra cu toàn cu thay vì mã byte tra cu cc b.

## 21.6 Phạm vi chức năng

Các cơ quan chc năng to ra phm vi địa phương.

Ví d:```python
def f(a, b):
    c = a + b
    return c
```Bên trong`f`:

```text
a       parameter + local
b       parameter + local
c       local
```Các tham s được coi là biến cc b được khi to.

Trình biên dch sau đó s phân b các v trí cho các v trí cc b bên trong đối tượng khung.

Giai đon bng ký hiu xác định:```text
how many local variables exist
which names are parameters
which bytecode instructions to emit
```## 21.7 Biến cục bộ

Tên được gán  bt k đâu trong hàm s tr thành tên cc b tr khi được khai báo khác.

Ví d:```python
x = 10

def f():
    print(x)
    x = 20
```Điu này làm tăng:```text
UnboundLocalError
```Ti sao?

Bi vì giai đon bng ký hiu nhìn thy s phân công`x`bên trong`f`:

```python
x = 20
```Điu đó có nghĩa là:```text
x is local to f
```Vì vy, trước đó:```python
print(x)
```c gng đọc địa phương`x`trước khi phân công.

Hành vi này xut phát t phân tích phm vi tĩnh ch không phi phng đoán thi gian chy.

## 21.8 Tuyên bố toàn cầu`global`thay đổi phân loại phạm vi.

Ví d:```python
x = 10

def f():
    global x
    x = 20
```Bây gi bng ký hiu ghi li:```text
x       global
```bên trong`f`.

Bài tp cp nht biến cp độ mô-đun.

Không có`global`, phép gán s to ra mt biến cc b.

Giai đon bng ký hiu phi x lý`global`khai báo trước khi biên dch các quyn truy cp tên.

## 21.9 Tuyên bố phi địa phương`nonlocal`đề cập đến các biến phạm vi chức năng kèm theo.

Ví d:```python
def outer():
    x = 10

    def inner():
        nonlocal x
        x += 1

    inner()
    return x
```Bên trong`inner`:

```text
x       free variable
```Bên trong`outer`:

```text
x       cell variable
```Biến ô là biến cc b được nm bt bi phm vi lng nhau.

Không có`nonlocal`, bài tp bên trong`inner`s to ra mt biến cc b mi.`nonlocal`nói vi bng ký hiu:```text
do not create a local binding
use enclosing function binding
```## 21.10 Biến miễn phí

Biến t do là tên được s dng bên trong mt phm vi nhưng được xác định trong phm vi hàm kèm theo.

Ví d:```python
def outer():
    x = 10

    def inner():
        return x
```Bên trong`inner`:

```text
x       free variable

xkhông phải là địa phươnginner.

Nó đến từouter.

Các biến miễn phí yêu cầu hỗ trợ đóng.

21.11 Biến ô

Biến ô là biến cục bộ được tham chiếu bởi phạm vi lồng nhau.

Ví dụ:```python def outer(): x = 10

def inner():
    return x

```Bên trongouter:

x       local + cell
```Tại sao?

Bởi vì`x`phải sống sót sau`outer`trở lại.

Hàm lồng nhau vẫn cần quyền truy cập vào nó.

CPython lưu trữ các biến đã ghi trong các ô đóng được phân bổ theo vùng heap thay vì các ô cục bộ chỉ có ngăn xếp thông thường.

Giai đoạn bảng ký hiệu xác định cục bộ nào cần lưu trữ ô.

## 21.12 Đóng cửa

Việc đóng cửa phụ thuộc trực tiếp vào phân tích bảng ký hiệu.

Ví dụ:```python
def make_counter():
    count = 0

    def inc():
        nonlocal count
        count += 1
        return count

    return inc
```Bảng ký hiệu xác định:```text
count in make_counter:
    local + cell

count in inc:
    free
```Trình biên dịch sau đó tạo ra máy đóng.

Khi chạy:```python
c = make_counter()
```trả về một hàm mang quyền truy cập vào`count`tế bào.

Nếu không có phân tích bảng ký hiệu, việc xây dựng kết thúc sẽ không thể thực hiện được.

## 21.13 Phân giải tên Danh mục

CPython phân loại rộng rãi tên thành các danh mục.

| Danh mục | Ý nghĩa |
| --------------- | -------------------------------- |
| Địa phương | Được xác định trong phạm vi hiện tại |
| Rõ ràng toàn cầu | Khai báo với`global`|
| Toàn cầu tiềm ẩn | Đã giải quyết ở cấp độ mô-đun/nội trang |
| Miễn phí | Đến từ phạm vi kèm theo |
| Tế bào | Địa phương được chụp bởi phạm vi lồng nhau |

Phân loại này kiểm soát việc tạo mã byte.

Ví dụ về danh mục mã byte:

| Danh mục | Họ mã byte |
| ----------- | --------------- |
| Địa phương |`LOAD_FAST`|
| Toàn cầu |`LOAD_GLOBAL`|
| Miễn phí/di động |`LOAD_DEREF`|
| Tra cứu tên |`LOAD_NAME`|

Các quyết định phạm vi khác nhau tạo ra hành vi và hiệu suất thời gian chạy khác nhau.

## 21.14 Mã byte phụ thuộc vào phân tích phạm vi

Ví dụ:```python
def f(a):
    return a
```Mã byte:```text
LOAD_FAST a
RETURN_VALUE

alà địa phương.

Hiện nay:```python x = 1

def f(): return x Mã byte:text LOAD_GLOBAL x RETURN_VALUE Bây giờ trường hợp đóng cửa:python def outer(): x = 1

def inner():
    return x

```Bên tronginner:

LOAD_DEREF x
RETURN_VALUE
```Chỉ riêng trình phân tích cú pháp không thể xác định được các hướng dẫn này.

Giai đoạn bảng ký hiệu cung cấp thông tin phạm vi cần thiết.

## 21.15 Phạm vi lớp học

Các thân lớp có hành vi phạm vi đặc biệt.

Ví dụ:```python
x = 1

class C:
    y = x
```Bên trong thân lớp:```text
y       local to class namespace
x       global
```Các thân lớp thực thi trong từ điển không gian tên của riêng chúng.

Nhưng các phương thức không tự động nắm bắt các biến phạm vi lớp về mặt từ vựng.

Ví dụ:```python
class C:
    x = 1

    def f(self):
        return x
```Điều này không truy cập`C.x`.

Tên`x`bên trong`f`được coi là toàn cục trừ khi được xác định khác.

Phạm vi lớp khác với phạm vi chức năng ở những điểm quan trọng.

## 21.16 Phạm vi hiểu

Sự hiểu biết Python hiện đại tạo ra phạm vi riêng của chúng.

Ví dụ:```python
x = 100

values = [x for x in range(3)]

print(x)
```Đầu ra:```text
100
```Biến hiểu không bị rò rỉ ra phạm vi bên ngoài.

Nội bộ:```text
comprehension creates nested scope
x inside comprehension is local there
outer x remains unchanged
```Các phiên bản Python trước đó hoạt động khác hẳn. CPython hiện đại sử dụng phạm vi hiểu riêng biệt.

## 21.17 Phạm vi biểu thức của trình tạo

Các biểu thức của trình tạo cũng tạo ra các phạm vi lồng nhau.

Ví dụ:```python
x = 10

g = (x for x in range(3))

print(x)
```bên ngoài`x`vẫn không thay đổi.

Biểu thức trình tạo hoạt động tương tự như một hàm lồng nhau ngầm định.

Giai đoạn bảng ký hiệu tạo ra thông tin ký hiệu riêng biệt cho phạm vi trình tạo.

## 21.18 Phạm vi Lambda

Biểu thức Lambda tạo phạm vi hàm.

Ví dụ:```python
x = 10

f = lambda y: x + y
```Bên trong lambda:```text
y       local parameter
x       free variable
```Lambda là các hàm ẩn danh nhưng việc phân tích bảng ký hiệu xử lý chúng tương tự như các hàm lồng nhau thông thường.

## 21.19 Nhập khẩu và Bảng ký hiệu

Nhập khẩu cũng ảnh hưởng đến bảng ký hiệu.

Ví dụ:```python
import os
from math import sin
```Ký hiệu phạm vi mô-đun:```text
os      imported local/global
sin     imported local/global
```Chức năng bên trong:```python
def f():
    import json

jsontrở thành địa phươngf.

Nhập khẩu là nhiệm vụ từ góc độ phân tích phạm vi.

21.20 Chú thích

Chú thích biến tham gia xử lý ký hiệu.

Ví dụ:python x: int = 1 Bảng ký hiệu ghi lại:text x assigned Chú thích chức năng cũng xuất hiện:```python def f(x: int) -> str: return str(x)


## 21.21 Các biến xử lý ngoại lệ

Tên trình x lý ngoi l to ra các ràng buc cc b.

Ví d:```python
try:
    run()
except ValueError as e:
    print(e)
```Bên trong khi ngoi l:```text
e       local
```CPython sau đó s xóa các biến ngoi l sau trình x lý để tránh các chu k tham chiếu liên quan đến truy nguyên.

Giai đon bng ký hiu xác định chính ràng buc đó. Hành vi dn dp xy ra sau đó.

## 21.22 Ràng buộc khớp mẫu

Khp mu gii thiu các quy tc ràng buc.

Ví d:```python
match value:
    case [x, y]:
        print(x, y)
```Các biến mu tr thành các ràng buc cc b.

Giai đon bng ký hiu phi phân bit:```text
pattern capture
ordinary expression
```bi vì cú pháp mu có ng nghĩa khác nhau.

## 21.23 Truyền tải AST trong quá trình phân tích biểu tượng

Giai đon bng biu tượng đi theo AST.

Mô hình đơn gin hóa:```text
visit Module
    create module scope

visit FunctionDef
    register function name
    create child scope
    visit parameters
    visit body

visit Assign
    mark targets as assigned
    visit expression

visit Name
    mark as load/store/delete

visit Global
    record explicit global declaration

visit Nonlocal
    record nonlocal declaration
```Vic truyn ti thu thp thông tin trước tiên, sau đó gii quyết các mi quan h phm vi.

## 21.24 Bản chất của phân tích phạm vi hai lần

Phân tích phm vi không hoàn toàn mang tính cc b.

Ví d:```python
def f():
    print(x)
    x = 1
```Ý nghĩa ca điu đầu tiên`x`ph thuc vào s phân công sau này.

Do đó CPython không th phân loi tên theo mt lượt t trái sang phi.

Giai đon bng ký hiu thu thp thông tin phm vi mt cách hiu qu trên toàn b khi trước khi phân loi cui cùng.

## 21.25 Cây phạm vi lồng nhau

Phm vi to thành mt cây.

Ví d:```python
x = 0

def outer():
    y = 1

    def inner():
        z = 2
```Cây phm vi:```text
Module
    outer
        inner
```Mi phm vi lưu tr các liên kết đến phm vi con.

Độ phân gii có th thay đổi t do hướng ra ngoài thông qua các phm vi kèm theo.

## 21.26 Nội dung

Nếu mt tên không được mô-đun cc b hay toàn cc xác định, thì vic tra cu thi gian chy có th quay li ni dung.

Ví d:```python
print(len([1, 2, 3]))
```Phm vi mô-đun bên trong:```text
print     implicit global/builtin
len       implicit global/builtin
```Giai đon bng ký hiu không gii quyết được các đối tượng dng sn thc tế. Nó phân loi phong cách tra cu.

Khi chy, tra cu toàn cu s kim tra:```text
module globals
then builtins
```## 21.27`symtable`mô-đun

Python hin th các bng ký hiu thông qua`symtable`mô-đun.

Ví d:```python
import symtable

src = """
x = 1

def outer():
    y = 2

    def inner():
        return x + y
"""

table = symtable.symtable(src, "<input>", "exec")

print(table.get_identifiers())
```Các bng ký hiu lng nhau có th được kim tra theo chương trình.

Mô-đun này hu ích cho:```text
linters
static analyzers
teaching scope behavior
compiler experiments
```## 21.28 Cấu trúc dữ liệu bảng biểu tượng trong CPython

Các khu vc ngun quan trng bao gm:```text
Python/symtable.c
Include/internal/
Python/compile.c
```Các bng biu tượng ca hàng máy móc:```text
scope type
symbol flags
child scopes
free variables
cell variables
parameter information
optimization flags
```C biu tượng mô t hành vi như:```text
assigned
used
parameter
global
nonlocal
free
cell
imported
annotated
```Trình biên dch sau đó s s dng siêu d liu này.

## 21.29 Tối ưu hóa và cục bộ

Phân tích phm vi cho phép truy cp biến cc b nhanh chóng.

Các biến cc b s dng các v trí được lp ch mc bên trong các khung.

Ví d:```python
def f(a, b):
    c = a + b
    return c
```Các ni dung cc b có th được biên dch thành các truy cp kiu mng:```text
locals[0] -> a
locals[1] -> b
locals[2] -> c
```Vic này nhanh hơn nhiu so vi vic tra cu t đin.

Nếu không có phân tích bng ký hiu, CPython không th tính toán trước b cc cc b.

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

S dng mô hình này:```text
The parser builds syntax structure.
The symbol table phase builds scope structure.
Each module, function, class, lambda, and comprehension creates a scope.
Names are classified as local, global, free, or cell variables.
Nested functions create closure relationships.
The compiler uses symbol table information to generate correct bytecode.
Fast locals, globals, and closures all depend on symbol analysis.
```Giai đon bng ký hiu là nơi CPython biến cú pháp thành ng nghĩa phm vi thc thi được.