6. 模塊?
退出 Python 解釋器后,再次進(jìn)入時(shí),之前在 Python 解釋器中定義的函數(shù)和變量就丟失了。因此,編寫(xiě)較長(zhǎng)程序時(shí),建議用文本編輯器代替解釋器,執(zhí)行文件中的輸入內(nèi)容,這就是編寫(xiě) 腳本 。隨著程序越來(lái)越長(zhǎng),為了方便維護(hù),最好把腳本拆分成多個(gè)文件。編寫(xiě)腳本還一個(gè)好處,不同程序調(diào)用同一個(gè)函數(shù)時(shí),不用每次把函數(shù)復(fù)制到各個(gè)程序。
為實(shí)現(xiàn)這些需求,Python 把各種定義存入一個(gè)文件,在腳本或解釋器的交互式實(shí)例中使用。這個(gè)文件就是 模塊 ;模塊中的定義可以 導(dǎo)入 到其他模塊或 主 模塊(在頂層和計(jì)算器模式下,執(zhí)行腳本中可訪問(wèn)的變量集)。
模塊是包含 Python 定義和語(yǔ)句的文件。其文件名是模塊名加后綴名 .py 。在模塊內(nèi)部,通過(guò)全局變量 __name__ 可以獲取模塊名(即字符串)。例如,用文本編輯器在當(dāng)前目錄下創(chuàng)建 fibo.py 文件,輸入以下內(nèi)容:
# Fibonacci numbers module
def fib(n): # write Fibonacci series up to n
a, b = 0, 1
while a < n:
print(a, end=' ')
a, b = b, a+b
print()
def fib2(n): # return Fibonacci series up to n
result = []
a, b = 0, 1
while a < n:
result.append(a)
a, b = b, a+b
return result
現(xiàn)在,進(jìn)入 Python 解釋器,用以下命令導(dǎo)入該模塊:
>>> import fibo
這項(xiàng)操作不直接把 fibo 函數(shù)定義的名稱(chēng)導(dǎo)入到當(dāng)前符號(hào)表,只導(dǎo)入模塊名 fibo 。要使用模塊名訪問(wèn)函數(shù):
>>> fibo.fib(1000)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987
>>> fibo.fib2(100)
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
>>> fibo.__name__
'fibo'
如果經(jīng)常使用某個(gè)函數(shù),可以把它賦值給局部變量:
>>> fib = fibo.fib
>>> fib(500)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377
6.1. 模塊詳解?
模塊包含可執(zhí)行語(yǔ)句及函數(shù)定義。這些語(yǔ)句用于初始化模塊,且僅在 import 語(yǔ)句 第一次 遇到模塊名時(shí)執(zhí)行。1 (文件作為腳本運(yùn)行時(shí),也會(huì)執(zhí)行這些語(yǔ)句。)
模塊有自己的私有符號(hào)表,用作模塊中所有函數(shù)的全局符號(hào)表。因此,在模塊內(nèi)使用全局變量時(shí),不用擔(dān)心與用戶(hù)定義的全局變量發(fā)生沖突。另一方面,可以用與訪問(wèn)模塊函數(shù)一樣的標(biāo)記法,訪問(wèn)模塊的全局變量,modname.itemname。
可以把其他模塊導(dǎo)入模塊。按慣例,所有 import 語(yǔ)句都放在模塊(或腳本)開(kāi)頭,但這不是必須的。導(dǎo)入的模塊名存在導(dǎo)入模塊的全局符號(hào)表里。
import 語(yǔ)句有一個(gè)變體,可以直接把模塊里的名稱(chēng)導(dǎo)入到另一個(gè)模塊的符號(hào)表。例如:
>>> from fibo import fib, fib2
>>> fib(500)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377
這段代碼不會(huì)把模塊名導(dǎo)入到局部符號(hào)表里(因此,本例沒(méi)有定義 fibo)。
還有一種變體可以導(dǎo)入模塊內(nèi)定義的所有名稱(chēng):
>>> from fibo import *
>>> fib(500)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377
這種方式會(huì)導(dǎo)入所有不以下劃線(_)開(kāi)頭的名稱(chēng)。大多數(shù)情況下,不要用這個(gè)功能,這種方式向解釋器導(dǎo)入了一批未知的名稱(chēng),可能會(huì)覆蓋已經(jīng)定義的名稱(chēng)。
注意,一般情況下,不建議從模塊或包內(nèi)導(dǎo)入 *, 因?yàn)?,這項(xiàng)操作經(jīng)常讓代碼變得難以理解。不過(guò),為了在交互式編譯器中少打幾個(gè)字,這么用也沒(méi)問(wèn)題。
模塊名后使用 as 時(shí),直接把 as 后的名稱(chēng)與導(dǎo)入模塊綁定。
>>> import fibo as fib
>>> fib.fib(500)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377
與 import fibo 一樣,這種方式也可以有效地導(dǎo)入模塊,唯一的區(qū)別是,導(dǎo)入的名稱(chēng)是 fib。
from 中也可以使用這種方式,效果類(lèi)似:
>>> from fibo import fib as fibonacci
>>> fibonacci(500)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377
備注
為了保證運(yùn)行效率,每次解釋器會(huì)話(huà)只導(dǎo)入一次模塊。如果更改了模塊內(nèi)容,必須重啟解釋器;僅交互測(cè)試一個(gè)模塊時(shí),也可以使用 importlib.reload(),例如 import importlib; importlib.reload(modulename)。
6.1.1. 以腳本方式執(zhí)行模塊?
可以用以下方式運(yùn)行 Python 模塊:
python fibo.py <arguments>
這項(xiàng)操作將執(zhí)行模塊里的代碼,和導(dǎo)入模塊一樣,但會(huì)把 __name__ 賦值為 "__main__"。 也就是把下列代碼添加到模塊末尾:
if __name__ == "__main__":
import sys
fib(int(sys.argv[1]))
既可以把這個(gè)文件當(dāng)腳本使用,也可以用作導(dǎo)入的模塊, 因?yàn)?,解析命令行的代碼只有在模塊以 “main” 文件執(zhí)行時(shí)才會(huì)運(yùn)行:
$ python fibo.py 50
0 1 1 2 3 5 8 13 21 34
導(dǎo)入模塊時(shí),不運(yùn)行這些代碼:
>>> import fibo
>>>
這種操作常用于為模塊提供便捷用戶(hù)接口,或用于測(cè)試(把模塊當(dāng)作執(zhí)行測(cè)試套件的腳本運(yùn)行)。
6.1.2. 模塊搜索路徑?
When a module named spam is imported, the interpreter first searches for
a built-in module with that name. These module names are listed in
sys.builtin_module_names. If not found, it then searches for a file
named spam.py in a list of directories given by the variable
sys.path. sys.path is initialized from these locations:
輸入腳本的目錄(或未指定文件時(shí)的當(dāng)前目錄)。
PYTHONPATH(目錄列表,與 shell 變量PATH的語(yǔ)法一樣)。The installation-dependent default (by convention including a
site-packagesdirectory, handled by thesitemodule).
More details are at The initialization of the sys.path module search path.
備注
在支持 symlink 的文件系統(tǒng)中,輸入腳本目錄是在追加 symlink 后計(jì)算出來(lái)的。換句話(huà)說(shuō),包含 symlink 的目錄并 沒(méi)有 添加至模塊搜索路徑。
初始化后,Python 程序可以更改 sys.path。運(yùn)行腳本的目錄在標(biāo)準(zhǔn)庫(kù)路徑之前,置于搜索路徑的開(kāi)頭。即,加載的是該目錄里的腳本,而不是標(biāo)準(zhǔn)庫(kù)的同名模塊。 除非刻意替換,否則會(huì)報(bào)錯(cuò)。詳見(jiàn) 標(biāo)準(zhǔn)模塊。
6.1.3. “已編譯的” Python 文件?
為了快速加載模塊,Python 把模塊的編譯版緩存在 __pycache__ 目錄中,文件名為 module.version.pyc,version 對(duì)編譯文件格式進(jìn)行編碼,一般是 Python 的版本號(hào)。例如,CPython 的 3.3 發(fā)行版中,spam.py 的編譯版本緩存為 __pycache__/spam.cpython-33.pyc。使用這種命名慣例,可以讓不同 Python 發(fā)行版及不同版本的已編譯模塊共存。
Python 對(duì)比編譯版本與源碼的修改日期,查看它是否已過(guò)期,是否要重新編譯,此過(guò)程完全自動(dòng)化。此外,編譯模塊與平臺(tái)無(wú)關(guān),因此,可在不同架構(gòu)系統(tǒng)之間共享相同的支持庫(kù)。
Python 在兩種情況下不檢查緩存。其一,從命令行直接載入模塊,只重新編譯,不存儲(chǔ)編譯結(jié)果;其二,沒(méi)有源模塊,就不會(huì)檢查緩存。為了支持無(wú)源文件(僅編譯)發(fā)行版本, 編譯模塊必須在源目錄下,并且絕不能有源模塊。
給專(zhuān)業(yè)人士的一些小建議:
在 Python 命令中使用
-O或-OO開(kāi)關(guān),可以減小編譯模塊的大小。-O去除斷言語(yǔ)句,-OO去除斷言語(yǔ)句和 __doc__ 字符串。有些程序可能依賴(lài)于這些內(nèi)容,因此,沒(méi)有十足的把握,不要使用這兩個(gè)選項(xiàng)?!皟?yōu)化過(guò)的”模塊帶有opt-標(biāo)簽,并且文件通常會(huì)一小些。將來(lái)的發(fā)行版或許會(huì)改進(jìn)優(yōu)化的效果。從
.pyc文件讀取的程序不比從.py讀取的執(zhí)行速度快,.pyc文件只是加載速度更快。compileall模塊可以為一個(gè)目錄下的所有模塊創(chuàng)建 .pyc 文件。本過(guò)程的細(xì)節(jié)及決策流程圖,詳見(jiàn) PEP 3147。
6.2. 標(biāo)準(zhǔn)模塊?
Python 自帶一個(gè)標(biāo)準(zhǔn)模塊的庫(kù),它在 Python 庫(kù)參考(此處以下稱(chēng)為"庫(kù)參考" )里另外描述。 一些模塊是內(nèi)嵌到編譯器里面的, 它們給一些雖并非語(yǔ)言核心但卻內(nèi)嵌的操作提供接口,要么是為了效率,要么是給操作系統(tǒng)基礎(chǔ)操作例如系統(tǒng)調(diào)入提供接口。 這些模塊集是一個(gè)配置選項(xiàng), 并且還依賴(lài)于底層的操作系統(tǒng)。 例如,winreg 模塊只在 Windows 系統(tǒng)上提供。一個(gè)特別值得注意的模塊 sys,它被內(nèi)嵌到每一個(gè) Python 編譯器中。sys.ps1 和 sys.ps2 變量定義了一些字符,它們可以用作主提示符和輔助提示符:
>>> import sys
>>> sys.ps1
'>>> '
>>> sys.ps2
'... '
>>> sys.ps1 = 'C> '
C> print('Yuck!')
Yuck!
C>
只有解釋器用于交互模式時(shí),才定義這兩個(gè)變量。
變量 sys.path 是字符串列表,用于確定解釋器的模塊搜索路徑。該變量以環(huán)境變量 PYTHONPATH 提取的默認(rèn)路徑進(jìn)行初始化,如未設(shè)置 PYTHONPATH,則使用內(nèi)置的默認(rèn)路徑。可以用標(biāo)準(zhǔn)列表操作修改該變量:
>>> import sys
>>> sys.path.append('/ufs/guido/lib/python')
6.3. dir() 函數(shù)?
內(nèi)置函數(shù) dir() 用于查找模塊定義的名稱(chēng)。返回結(jié)果是經(jīng)過(guò)排序的字符串列表:
>>> import fibo, sys
>>> dir(fibo)
['__name__', 'fib', 'fib2']
>>> dir(sys)
['__breakpointhook__', '__displayhook__', '__doc__', '__excepthook__',
'__interactivehook__', '__loader__', '__name__', '__package__', '__spec__',
'__stderr__', '__stdin__', '__stdout__', '__unraisablehook__',
'_clear_type_cache', '_current_frames', '_debugmallocstats', '_framework',
'_getframe', '_git', '_home', '_xoptions', 'abiflags', 'addaudithook',
'api_version', 'argv', 'audit', 'base_exec_prefix', 'base_prefix',
'breakpointhook', 'builtin_module_names', 'byteorder', 'call_tracing',
'callstats', 'copyright', 'displayhook', 'dont_write_bytecode', 'exc_info',
'excepthook', 'exec_prefix', 'executable', 'exit', 'flags', 'float_info',
'float_repr_style', 'get_asyncgen_hooks', 'get_coroutine_origin_tracking_depth',
'getallocatedblocks', 'getdefaultencoding', 'getdlopenflags',
'getfilesystemencodeerrors', 'getfilesystemencoding', 'getprofile',
'getrecursionlimit', 'getrefcount', 'getsizeof', 'getswitchinterval',
'gettrace', 'hash_info', 'hexversion', 'implementation', 'int_info',
'intern', 'is_finalizing', 'last_traceback', 'last_type', 'last_value',
'maxsize', 'maxunicode', 'meta_path', 'modules', 'path', 'path_hooks',
'path_importer_cache', 'platform', 'prefix', 'ps1', 'ps2', 'pycache_prefix',
'set_asyncgen_hooks', 'set_coroutine_origin_tracking_depth', 'setdlopenflags',
'setprofile', 'setrecursionlimit', 'setswitchinterval', 'settrace', 'stderr',
'stdin', 'stdout', 'thread_info', 'unraisablehook', 'version', 'version_info',
'warnoptions']
沒(méi)有參數(shù)時(shí),dir() 列出當(dāng)前定義的名稱(chēng):
>>> a = [1, 2, 3, 4, 5]
>>> import fibo
>>> fib = fibo.fib
>>> dir()
['__builtins__', '__name__', 'a', 'fib', 'fibo', 'sys']
注意,該函數(shù)列出所有類(lèi)型的名稱(chēng):變量、模塊、函數(shù)等。
dir() 不會(huì)列出內(nèi)置函數(shù)和變量的名稱(chēng)。這些內(nèi)容的定義在標(biāo)準(zhǔn)模塊 builtins 里:
>>> import builtins
>>> dir(builtins)
['ArithmeticError', 'AssertionError', 'AttributeError', 'BaseException',
'BlockingIOError', 'BrokenPipeError', 'BufferError', 'BytesWarning',
'ChildProcessError', 'ConnectionAbortedError', 'ConnectionError',
'ConnectionRefusedError', 'ConnectionResetError', 'DeprecationWarning',
'EOFError', 'Ellipsis', 'EnvironmentError', 'Exception', 'False',
'FileExistsError', 'FileNotFoundError', 'FloatingPointError',
'FutureWarning', 'GeneratorExit', 'IOError', 'ImportError',
'ImportWarning', 'IndentationError', 'IndexError', 'InterruptedError',
'IsADirectoryError', 'KeyError', 'KeyboardInterrupt', 'LookupError',
'MemoryError', 'NameError', 'None', 'NotADirectoryError', 'NotImplemented',
'NotImplementedError', 'OSError', 'OverflowError',
'PendingDeprecationWarning', 'PermissionError', 'ProcessLookupError',
'ReferenceError', 'ResourceWarning', 'RuntimeError', 'RuntimeWarning',
'StopIteration', 'SyntaxError', 'SyntaxWarning', 'SystemError',
'SystemExit', 'TabError', 'TimeoutError', 'True', 'TypeError',
'UnboundLocalError', 'UnicodeDecodeError', 'UnicodeEncodeError',
'UnicodeError', 'UnicodeTranslateError', 'UnicodeWarning', 'UserWarning',
'ValueError', 'Warning', 'ZeroDivisionError', '_', '__build_class__',
'__debug__', '__doc__', '__import__', '__name__', '__package__', 'abs',
'all', 'any', 'ascii', 'bin', 'bool', 'bytearray', 'bytes', 'callable',
'chr', 'classmethod', 'compile', 'complex', 'copyright', 'credits',
'delattr', 'dict', 'dir', 'divmod', 'enumerate', 'eval', 'exec', 'exit',
'filter', 'float', 'format', 'frozenset', 'getattr', 'globals', 'hasattr',
'hash', 'help', 'hex', 'id', 'input', 'int', 'isinstance', 'issubclass',
'iter', 'len', 'license', 'list', 'locals', 'map', 'max', 'memoryview',
'min', 'next', 'object', 'oct', 'open', 'ord', 'pow', 'print', 'property',
'quit', 'range', 'repr', 'reversed', 'round', 'set', 'setattr', 'slice',
'sorted', 'staticmethod', 'str', 'sum', 'super', 'tuple', 'type', 'vars',
'zip']
6.4. 包?
包是一種用“點(diǎn)式模塊名”構(gòu)造 Python 模塊命名空間的方法。例如,模塊名 A.B 表示包 A 中名為 B 的子模塊。正如模塊可以區(qū)分不同模塊之間的全局變量名稱(chēng)一樣,點(diǎn)式模塊名可以區(qū)分 NumPy 或 Pillow 等不同多模塊包之間的模塊名稱(chēng)。
假設(shè)要為統(tǒng)一處理聲音文件與聲音數(shù)據(jù)設(shè)計(jì)一個(gè)模塊集(“包”)。聲音文件的格式很多(通常以擴(kuò)展名來(lái)識(shí)別,例如:.wav, .aiff, .au),因此,為了不同文件格式之間的轉(zhuǎn)換,需要?jiǎng)?chuàng)建和維護(hù)一個(gè)不斷增長(zhǎng)的模塊集合。為了實(shí)現(xiàn)對(duì)聲音數(shù)據(jù)的不同處理(例如,混聲、添加回聲、均衡器功能、創(chuàng)造人工立體聲效果),還要編寫(xiě)無(wú)窮無(wú)盡的模塊流。下面這個(gè)分級(jí)文件樹(shù)展示了這個(gè)包的架構(gòu):
sound/ Top-level package
__init__.py Initialize the sound package
formats/ Subpackage for file format conversions
__init__.py
wavread.py
wavwrite.py
aiffread.py
aiffwrite.py
auread.py
auwrite.py
...
effects/ Subpackage for sound effects
__init__.py
echo.py
surround.py
reverse.py
...
filters/ Subpackage for filters
__init__.py
equalizer.py
vocoder.py
karaoke.py
...
導(dǎo)入包時(shí),Python 搜索 sys.path 里的目錄,查找包的子目錄。
Python 只把含 __init__.py 文件的目錄當(dāng)成包。這樣可以防止以 string 等通用名稱(chēng)命名的目錄,無(wú)意中屏蔽出現(xiàn)在后方模塊搜索路徑中的有效模塊。 最簡(jiǎn)情況下,__init__.py 只是一個(gè)空文件,但該文件也可以執(zhí)行包的初始化代碼,或設(shè)置 __all__ 變量,詳見(jiàn)下文。
還可以從包中導(dǎo)入單個(gè)模塊,例如:
import sound.effects.echo
這段代碼加載子模塊 sound.effects.echo ,但引用時(shí)必須使用子模塊的全名:
sound.effects.echo.echofilter(input, output, delay=0.7, atten=4)
另一種導(dǎo)入子模塊的方法是 :
from sound.effects import echo
這段代碼還可以加載子模塊 echo ,不加包前綴也可以使用。因此,可以按如下方式使用:
echo.echofilter(input, output, delay=0.7, atten=4)
Import 語(yǔ)句的另一種變體是直接導(dǎo)入所需的函數(shù)或變量:
from sound.effects.echo import echofilter
同樣,這樣也會(huì)加載子模塊 echo,但可以直接使用函數(shù) echofilter():
echofilter(input, output, delay=0.7, atten=4)
注意,使用 from package import item 時(shí),item 可以是包的子模塊(或子包),也可以是包中定義的函數(shù)、類(lèi)或變量等其他名稱(chēng)。import 語(yǔ)句首先測(cè)試包中是否定義了 item;如果未在包中定義,則假定 item 是模塊,并嘗試加載。如果找不到 item,則觸發(fā) ImportError 異常。
相反,使用 import item.subitem.subsubitem 句法時(shí),除最后一項(xiàng)外,每個(gè) item 都必須是包;最后一項(xiàng)可以是模塊或包,但不能是上一項(xiàng)中定義的類(lèi)、函數(shù)或變量。
6.4.1. 從包中導(dǎo)入 *?
使用 from sound.effects import * 時(shí)會(huì)發(fā)生什么?理想情況下,該語(yǔ)句在文件系統(tǒng)查找并導(dǎo)入包的所有子模塊。這項(xiàng)操作花費(fèi)的時(shí)間較長(zhǎng),并且導(dǎo)入子模塊可能會(huì)產(chǎn)生不必要的副作用,這種副作用只有在顯式導(dǎo)入子模塊時(shí)才會(huì)發(fā)生。
唯一的解決方案是提供包的顯式索引。import 語(yǔ)句使用如下慣例:如果包的 __init__.py 代碼定義了列表 __all__,運(yùn)行 from package import * 時(shí),它就是用于導(dǎo)入的模塊名列表。發(fā)布包的新版本時(shí),包的作者應(yīng)更新此列表。如果包的作者認(rèn)為沒(méi)有必要在包中執(zhí)行導(dǎo)入 * 操作,也可以不提供此列表。例如,sound/effects/__init__.py 文件包含以下代碼:
__all__ = ["echo", "surround", "reverse"]
This would mean that from sound.effects import * would import the three
named submodules of the sound.effects package.
如果沒(méi)有定義 __all__,from sound.effects import * 語(yǔ)句 不會(huì) 把包 sound.effects 中所有子模塊都導(dǎo)入到當(dāng)前命名空間;該語(yǔ)句只確保導(dǎo)入包 sound.effects (可能還會(huì)運(yùn)行 __init__.py 中的初始化代碼),然后,再導(dǎo)入包中定義的名稱(chēng)。這些名稱(chēng)包括 __init__.py 中定義的任何名稱(chēng)(以及顯式加載的子模塊),還包括之前 import 語(yǔ)句顯式加載的包里的子模塊。請(qǐng)看以下代碼:
import sound.effects.echo
import sound.effects.surround
from sound.effects import *
本例中,執(zhí)行 from...import 語(yǔ)句時(shí),將把 echo 和 surround 模塊導(dǎo)入至當(dāng)前命名空間,因?yàn)?,它們是?sound.effects 包里定義的。(該導(dǎo)入操作在定義了 __all__ 時(shí)也有效。)
雖然,可以把模塊設(shè)計(jì)為用 import * 時(shí)只導(dǎo)出遵循指定模式的名稱(chēng),但仍不提倡在生產(chǎn)代碼中使用這種做法。
記住,使用 from package import specific_submodule 沒(méi)有任何問(wèn)題! 實(shí)際上,除了導(dǎo)入模塊使用不同包的同名子模塊之外,這種方式是推薦用法。
6.4.2. 子包參考?
包中含有多個(gè)子包時(shí)(與示例中的 sound 包一樣),可以使用絕對(duì)導(dǎo)入引用兄弟包中的子模塊。例如,要在模塊 sound.filters.vocoder 中使用 sound.effects 包的 echo 模塊時(shí),可以用 from sound.effects import echo 導(dǎo)入。
還可以用 import 語(yǔ)句的 from module import name 形式執(zhí)行相對(duì)導(dǎo)入。這些導(dǎo)入語(yǔ)句使用前導(dǎo)句點(diǎn)表示相對(duì)導(dǎo)入中的當(dāng)前包和父包。例如,相對(duì)于 surround 模塊,可以使用:
from . import echo
from .. import formats
from ..filters import equalizer
注意,相對(duì)導(dǎo)入基于當(dāng)前模塊名。因?yàn)橹髂K名是 "__main__" ,所以 Python 程序的主模塊必須始終使用絕對(duì)導(dǎo)入。
6.4.3. 多目錄中的包?
包還支持特殊屬性 __path__。該屬性初始化為在包的 __init__.py 文件中的代碼執(zhí)行前所在的目錄名列表。這個(gè)變量可以修改,但這樣做會(huì)影響將來(lái)搜索包中模塊和子包的操作。
這個(gè)功能雖然不常用,但可用于擴(kuò)展包中的模塊集。
備注
- 1
實(shí)際上,函數(shù)定義也是“可執(zhí)行”的“語(yǔ)句”;執(zhí)行模塊級(jí)函數(shù)定義時(shí),函數(shù)名將被導(dǎo)入到模塊的全局符號(hào)表。