dis — Python 位元組碼反彙編器

原始碼: Lib/dis.py


dis 模組支援透過反彙編來分析 CPython 位元組碼 。此模組作為輸入的 CPython 位元組碼在檔案 Include/opcode.h 中定義,並由編譯器和直譯器使用。

CPython 實現細節: 位元組碼是 CPython 直譯器的實現細節。不保證位元組碼在 Python 版本之間不會被新增、刪除或更改。本模組的使用不應被認為可以在不同的 Python 虛擬機器或 Python 版本之間工作。

在 3.6 版本中更改: 每條指令使用 2 個位元組。以前位元組數因指令而異。

在 3.10 版本中更改: 跳轉、異常處理和迴圈指令的引數現在是指令偏移而不是位元組偏移。

在 3.11 版本中更改: 一些指令會伴隨一個或多個內聯快取條目,這些條目採用 CACHE 指令的形式。這些指令預設是隱藏的,但是可以透過傳遞 show_caches=True 到任何 dis 實用程式來顯示。此外,直譯器現在會調整位元組碼以針對不同的執行時條件進行專門化。可以透過傳遞 adaptive=True 來顯示自適應位元組碼。

在 3.12 版本中更改: 跳轉的引數是目標指令相對於跳轉指令的 CACHE 條目之後立即出現的指令的偏移量。

因此,CACHE 指令的存在對於前向跳轉是透明的,但在推理後向跳轉時需要考慮。

在 3.13 版本中更改: 輸出顯示跳轉目標和異常處理程式的邏輯標籤,而不是指令偏移量。添加了 -O 命令列選項和 show_offsets 引數。

例如:給定函式 myfunc()

def myfunc(alist):
    return len(alist)

可以使用以下命令來顯示 myfunc() 的反彙編

>>> dis.dis(myfunc)
  2           RESUME                   0

  3           LOAD_GLOBAL              1 (len + NULL)
              LOAD_FAST                0 (alist)
              CALL                     1
              RETURN_VALUE

(“2” 是行號)。

命令列介面

可以從命令列將 dis 模組作為指令碼呼叫

python -m dis [-h] [-C] [-O] [infile]

接受以下選項

-h, --help

顯示用法並退出。

-C, --show-caches

顯示內聯快取。

-O, --show-offsets

顯示指令的偏移量。

如果指定了 infile ,則其反彙編程式碼將被寫入 stdout。否則,將對從 stdin 接收的已編譯原始碼執行反彙編。

位元組碼分析

3.4 版本新增。

位元組碼分析 API 允許將 Python 程式碼片段包裝在 Bytecode 物件中,該物件提供對已編譯程式碼細節的輕鬆訪問。

class dis.Bytecode(x, *, first_line=None, current_offset=None, show_caches=False, adaptive=False, show_offsets=False)

分析與函式、生成器、非同步生成器、協程、方法、原始碼字串或程式碼物件(由 compile() 返回)相對應的位元組碼。

這是對下面列出的許多函式的便捷包裝,最值得注意的是 get_instructions(),因為迭代 Bytecode 例項會生成位元組碼操作作為 Instruction 例項。

如果 first_line 不是 None,則表示應為反彙編程式碼中的第一個原始碼行報告的行號。否則,原始碼行資訊(如果有)直接取自反彙編程式碼物件。

如果 current_offset 不是 None,則它指的是反彙編程式碼中的指令偏移量。設定此項意味著 dis() 將在指定的 opcode 上顯示“當前指令”標記。

如果 show_cachesTrue,則 dis() 將顯示直譯器用於專門化位元組碼的內聯快取條目。

如果 adaptiveTrue,則 dis() 將顯示可能與原始位元組碼不同的專門化位元組碼。

如果 show_offsetsTrue,則 dis() 將在輸出中包含指令偏移量。

classmethod from_traceback(tb, *, show_caches=False)

從給定的回溯構造一個 Bytecode 例項,將 current_offset 設定為導致異常的指令。

codeobj

編譯後的程式碼物件。

first_line

程式碼物件的第一個原始碼行(如果可用)

dis()

返回位元組碼操作的格式化檢視(與 dis.dis() 列印的內容相同,但作為多行字串返回)。

info()

返回包含有關程式碼物件的詳細資訊的格式化多行字串,如 code_info()

在 3.7 版本中更改: 現在可以處理協程和非同步生成器物件。

在 3.11 版本中更改: 添加了 show_cachesadaptive 引數。

示例

>>> bytecode = dis.Bytecode(myfunc)
>>> for instr in bytecode:
...     print(instr.opname)
...
RESUME
LOAD_GLOBAL
LOAD_FAST
CALL
RETURN_VALUE

分析函式

dis 模組還定義了以下分析函式,它們直接將輸入轉換為所需的輸出。如果只執行一個操作,那麼中間的分析物件就沒什麼用處,這些函式就很有用。

dis.code_info(x)

返回一個格式化的多行字串,其中包含為提供的函式、生成器、非同步生成器、協程、方法、原始碼字串或程式碼物件提供的詳細程式碼物件資訊。

請注意,程式碼資訊字串的確切內容高度依賴於實現,並且它們可能會在 Python VM 或 Python 版本之間任意更改。

3.2 版本新增。

在 3.7 版本中更改: 現在可以處理協程和非同步生成器物件。

dis.show_code(x, *, file=None)

將提供的函式、方法、原始碼字串或程式碼物件的詳細程式碼物件資訊列印到 file(如果未指定 file,則列印到 sys.stdout)。

這是 print(code_info(x), file=file) 的便捷簡寫,旨在用於直譯器提示符下的互動式探索。

3.2 版本新增。

在 3.4 版本中更改: 添加了 file 引數。

dis.dis(x=None, *, file=None, depth=None, show_caches=False, adaptive=False)

反彙編 x 物件。 x 可以表示模組、類、方法、函式、生成器、非同步生成器、協程、程式碼物件、原始碼字串或原始位元組碼的位元組序列。 對於模組,它會反彙編所有函式。 對於類,它會反彙編所有方法(包括類方法和靜態方法)。 對於程式碼物件或原始位元組碼序列,它會為每個位元組碼指令列印一行。 它還會遞迴地反彙編巢狀的程式碼物件。 這些可以包括生成器表示式、巢狀函式、巢狀類的主體以及用於註解作用域的程式碼物件。 字串首先使用 compile() 內建函式編譯為程式碼物件,然後再進行反彙編。 如果未提供任何物件,則此函式會反彙編最後一個回溯。

反彙編以文字形式寫入提供的 file 引數(如果提供),否則寫入 sys.stdout

遞迴的最大深度受 depth 限制,除非它是 Nonedepth=0 表示不遞迴。

如果 show_cachesTrue,此函式將顯示直譯器用於專門化位元組碼的內聯快取條目。

如果 adaptiveTrue,此函式將顯示可能與原始位元組碼不同的專用位元組碼。

在 3.4 版本中更改: 添加了 file 引數。

在 3.7 版本中更改: 實現了遞迴反彙編並添加了 depth 引數。

在 3.7 版本中更改: 現在可以處理協程和非同步生成器物件。

在 3.11 版本中更改: 添加了 show_cachesadaptive 引數。

distb(tb=None, *, file=None, show_caches=False, adaptive=False,
show_offset=False)

反彙編回溯的堆疊頂層函式,如果沒有傳遞迴溯,則使用最後一個回溯。 指示導致異常的指令。

反彙編以文字形式寫入提供的 file 引數(如果提供),否則寫入 sys.stdout

在 3.4 版本中更改: 添加了 file 引數。

在 3.11 版本中更改: 添加了 show_cachesadaptive 引數。

在 3.13 版本中更改: 添加了 show_offsets 引數。

dis.disassemble(code, lasti=-1, *, file=None, show_caches=False, adaptive=False)
disco(code, lasti=-1, *, file=None, show_caches=False, adaptive=False,
show_offsets=False)

反彙編程式碼物件,如果提供了 lasti,則指示最後一條指令。 輸出分為以下幾列:

  1. 行號,對於每行的第一條指令

  2. 當前指令,指示為 -->

  3. 標記的指令,指示為 >>

  4. 指令的地址,

  5. 操作碼名稱,

  6. 操作引數,以及

  7. 括號中引數的解釋。

引數解釋識別區域性和全域性變數名、常量值、分支目標和比較運算子。

反彙編以文字形式寫入提供的 file 引數(如果提供),否則寫入 sys.stdout

在 3.4 版本中更改: 添加了 file 引數。

在 3.11 版本中更改: 添加了 show_cachesadaptive 引數。

在 3.13 版本中更改: 添加了 show_offsets 引數。

dis.get_instructions(x, *, first_line=None, show_caches=False, adaptive=False)

返回提供的函式、方法、原始碼字串或程式碼物件中指令的迭代器。

迭代器生成一系列 Instruction 命名元組,其中提供了所提供程式碼中每個操作的詳細資訊。

如果 first_line 不是 None,則表示應為反彙編程式碼中的第一個原始碼行報告的行號。否則,原始碼行資訊(如果有)直接取自反彙編程式碼物件。

adaptive 引數的工作方式與 dis() 中相同。

3.4 版本新增。

在 3.11 版本中更改: 添加了 show_cachesadaptive 引數。

在 3.13 版本中更改: show_caches 引數已棄用,不起作用。 迭代器生成具有 cache_info 欄位填充的 Instruction 例項(無論 show_caches 的值如何),並且它不再為快取條目生成單獨的項。

dis.findlinestarts(code)

此生成器函式使用 co_lines() 方法的 程式碼物件 code 來查詢原始碼中行開始的偏移量。 它們以 (offset, lineno) 對的形式生成。

在 3.6 版本中更改: 行號可能會遞減。 以前,它們總是遞增的。

在 3.10 版本中更改: 使用 PEP 626 co_lines() 方法,而不是 co_firstlinenoco_lnotab 屬性的 程式碼物件

在 3.13 版本中更改: 對於不對映到原始碼行的位元組碼,行號可以為 None

dis.findlabels(code)

檢測原始編譯位元組碼字串 code 中所有作為跳轉目標的偏移量,並返回這些偏移量的列表。

dis.stack_effect(opcode, oparg=None, *, jump=None)

計算具有引數 opargopcode 的堆疊效應。

如果程式碼具有跳轉目標並且jumpTrue,則 stack_effect() 將返回跳轉的堆疊效應。如果 jumpFalse,它將返回不跳轉的堆疊效應。如果 jumpNone (預設值),它將返回兩種情況的最大堆疊效應。

3.4 版本新增。

在 3.8 版本中更改: 添加了 jump 引數。

在 3.13 版本中更改: 如果省略 oparg (或 None),現在將返回 oparg=0 的堆疊效應。之前,對於使用其引數的操作碼,這是一個錯誤。當 opcode 不使用 oparg 時,傳遞整數 oparg 也不再是錯誤;在這種情況下,oparg 將被忽略。

Python 位元組碼指令

get_instructions() 函式和 Bytecode 類以 Instruction 例項的形式提供位元組碼指令的詳細資訊

class dis.Instruction

位元組碼操作的詳細資訊

opcode

操作的數字程式碼,對應於下面列出的操作碼值和 操作碼集合 中的位元組碼值。

opname

操作的人類可讀名稱

baseopcode

如果操作是專門的,則為基本操作的數字程式碼;否則等於 opcode

baseopname

如果操作是專門的,則為基本操作的人類可讀名稱;否則等於 opname

arg

操作的數字引數(如果有),否則為 None

oparg

arg 的別名

argval

已解析的引數值(如果有),否則為 None

argrepr

操作引數的人類可讀描述(如果有),否則為空字串。

offset

操作在位元組碼序列中的起始索引

start_offset

操作在位元組碼序列中的起始索引,包括字首的 EXTENDED_ARG 操作(如果存在);否則等於 offset

cache_offset

操作之後的快取條目的起始索引

end_offset

操作之後的快取條目的結束索引

starts_line

如果此操作碼開始一個原始碼行,則為 True,否則為 False

line_number

與此操作碼關聯的原始碼行號(如果有),否則為 None

is_jump_target

如果有其他程式碼跳轉到此處,則為 True,否則為 False

jump_target

如果這是一個跳轉操作,則為跳轉目標的位元組碼索引,否則為 None

positions

儲存此指令覆蓋的起始和結束位置的 dis.Positions 物件。

3.4 版本新增。

在 3.11 版本中更改: 添加了 positions 欄位。

在 3.13 版本中更改: 更改了 starts_line 欄位。

添加了欄位 start_offsetcache_offsetend_offsetbaseopnamebaseopcodejump_targetopargline_numbercache_info

class dis.Positions

如果資訊不可用,某些欄位可能為 None

lineno
end_lineno
col_offset
end_col_offset

在 3.11 版本中新增。

Python 編譯器當前生成以下位元組碼指令。

通用指令

在下面,我們將直譯器堆疊稱為 STACK,並描述對其的操作,就好像它是一個 Python 列表一樣。堆疊的頂部對應於此語言中的 STACK[-1]

NOP

無操作程式碼。用作位元組碼最佳化器的佔位符,並生成行跟蹤事件。

POP_TOP

刪除堆疊頂部的專案

STACK.pop()
END_FOR

刪除堆疊頂部的專案。等效於 POP_TOP。用於在迴圈結束時清理,因此得名。

在 3.12 版本中新增。

END_SEND

實現 del STACK[-2]。用於在生成器退出時清理。

在 3.12 版本中新增。

COPY(i)

將第 i 個專案推送到堆疊頂部,而無需將其從原始位置刪除

assert i > 0
STACK.append(STACK[-i])

在 3.11 版本中新增。

SWAP(i)

將堆疊頂部與第 i 個元素交換

STACK[-i], STACK[-1] = STACK[-1], STACK[-i]

在 3.11 版本中新增。

CACHE

此操作碼並非實際指令,而是用於標記額外的空間,供直譯器直接在位元組碼本身中快取有用的資料。它會被所有 dis 實用工具自動隱藏,但可以使用 show_caches=True 檢視。

從邏輯上講,此空間是前一條指令的一部分。許多操作碼都期望後跟確切數量的快取,並會指示直譯器在執行時跳過這些快取。

填充的快取可能看起來像任意指令,因此在讀取或修改包含加速資料的原始自適應位元組碼時應格外小心。

在 3.11 版本中新增。

一元運算

一元運算會獲取堆疊頂部的值,應用運算,並將結果推回堆疊。

UNARY_NEGATIVE

實現 STACK[-1] = -STACK[-1]

UNARY_NOT

實現 STACK[-1] = not STACK[-1]

在 3.13 版本中更改: 此指令現在要求一個精確的 bool 運算元。

UNARY_INVERT

實現 STACK[-1] = ~STACK[-1]

GET_ITER

實現 STACK[-1] = iter(STACK[-1])

GET_YIELD_FROM_ITER

如果 STACK[-1] 是一個 生成器迭代器協程 物件,則保持不變。否則,實現 STACK[-1] = iter(STACK[-1])

在 3.5 版本中新增。

TO_BOOL

實現 STACK[-1] = bool(STACK[-1])

在 3.13 版本中新增。

二元和原地操作

二元運算會從堆疊中移除頂部的兩個項(STACK[-1]STACK[-2])。它們執行運算,然後將結果放回堆疊。

原地運算類似於二元運算,但當 STACK[-2] 支援時,運算會在原地完成,並且生成的 STACK[-1] 可以是(但不一定必須是)原始的 STACK[-2]

BINARY_OP(op)

實現二元和原地運算子(取決於 op 的值)

rhs = STACK.pop()
lhs = STACK.pop()
STACK.append(lhs op rhs)

在 3.11 版本中新增。

BINARY_SUBSCR

實現

key = STACK.pop()
container = STACK.pop()
STACK.append(container[key])
STORE_SUBSCR

實現

key = STACK.pop()
container = STACK.pop()
value = STACK.pop()
container[key] = value
DELETE_SUBSCR

實現

key = STACK.pop()
container = STACK.pop()
del container[key]
BINARY_SLICE

實現

end = STACK.pop()
start = STACK.pop()
container = STACK.pop()
STACK.append(container[start:end])

在 3.12 版本中新增。

STORE_SLICE

實現

end = STACK.pop()
start = STACK.pop()
container = STACK.pop()
values = STACK.pop()
container[start:end] = value

在 3.12 版本中新增。

協程操作碼

GET_AWAITABLE(where)

實現 STACK[-1] = get_awaitable(STACK[-1]),其中如果 o 是協程物件或具有 CO_ITERABLE_COROUTINE 標誌的生成器物件,則 get_awaitable(o) 返回 o,或解析 o.__await__

如果 where 運算元非零,則表示指令出現的位置

  • 1: 在呼叫 __aenter__ 之後

  • 2: 在呼叫 __aexit__ 之後

在 3.5 版本中新增。

在 3.11 版本中更改: 以前,此指令沒有運算元。

GET_AITER

實現 STACK[-1] = STACK[-1].__aiter__()

在 3.5 版本中新增。

在 3.7 版本中更改: 不再支援從 __aiter__ 返回可等待物件。

GET_ANEXT

STACK.append(get_awaitable(STACK[-1].__anext__())) 實現到堆疊。有關 get_awaitable 的詳細資訊,請參閱 GET_AWAITABLE

在 3.5 版本中新增。

END_ASYNC_FOR

終止 async for 迴圈。處理等待下一個項時引發的異常。堆疊包含 STACK[-2] 中的非同步可迭代物件和 STACK[-1] 中引發的異常。兩者都會被彈出。如果異常不是 StopAsyncIteration,則會重新引發。

在 3.8 版本中新增。

在 3.11 版本中更改: 堆疊上的異常表示現在由一項而不是三項組成。

CLEANUP_THROW

處理在當前幀中透過 throw()close() 呼叫期間引發的異常。如果 STACK[-1]StopIteration 的例項,則從堆疊中彈出三個值並推送其 value 成員。否則,重新引發 STACK[-1]

在 3.12 版本中新增。

BEFORE_ASYNC_WITH

STACK[-1] 解析 __aenter____aexit__。將 __aexit____aenter__() 的結果推送到堆疊

STACK.extend((__aexit__, __aenter__())

在 3.5 版本中新增。

雜項操作碼

SET_ADD(i)

實現

item = STACK.pop()
set.add(STACK[-i], item)

用於實現集合推導式。

LIST_APPEND(i)

實現

item = STACK.pop()
list.append(STACK[-i], item)

用於實現列表推導式。

MAP_ADD(i)

實現

value = STACK.pop()
key = STACK.pop()
dict.__setitem__(STACK[-i], key, value)

用於實現字典推導式。

在 3.1 版本中新增。

在 3.8 版本中更改: 對映值為 STACK[-1],對映鍵為 STACK[-2]。之前,它們是反向的。

對於所有 SET_ADDLIST_APPENDMAP_ADD 指令,在新增的值或鍵/值對被彈出時,容器物件仍然保留在堆疊上,以便在迴圈的進一步迭代中可用。

RETURN_VALUE

STACK[-1] 返回給函式的呼叫者。

RETURN_CONST(consti)

co_consts[consti] 返回給函式的呼叫者。

在 3.12 版本中新增。

YIELD_VALUE

生成器 中產生 STACK.pop()

在 3.11 版本中更改: oparg 設定為堆疊深度。

在 3.12 版本中更改: oparg 設定為異常塊深度,以便高效關閉生成器。

在 3.13 版本中更改: 如果此指令是 yield-from 或 await 的一部分,則 oparg 為 1,否則為 0

SETUP_ANNOTATIONS

檢查 __annotations__ 是否在 locals() 中定義,如果未定義,則將其設定為一個空的 dict。只有當類或模組主體靜態包含變數註解時,才會發出此操作碼。

在 3.6 版本中加入。

POP_EXCEPT

從堆疊中彈出一個值,用於恢復異常狀態。

在 3.11 版本中更改: 堆疊上的異常表示現在由一項而不是三項組成。

RERAISE

重新引發當前在堆疊頂部的異常。如果 oparg 非零,則從堆疊中彈出一個附加值,該值用於設定當前幀的 f_lasti

在 3.9 版本中加入。

在 3.11 版本中更改: 堆疊上的異常表示現在由一項而不是三項組成。

PUSH_EXC_INFO

從堆疊中彈出一個值。將當前異常推送到堆疊頂部。將最初彈出的值推回堆疊。用於異常處理程式中。

在 3.11 版本中新增。

CHECK_EXC_MATCH

except 執行異常匹配。測試 STACK[-2] 是否是一個與 STACK[-1] 匹配的異常。彈出 STACK[-1] 並推送測試的布林結果。

在 3.11 版本中新增。

CHECK_EG_MATCH

except* 執行異常匹配。在表示 STACK[-2] 的異常組上應用 split(STACK[-1])

如果匹配,則從堆疊中彈出兩項,並推送不匹配的子組(如果完全匹配,則為 None),後跟匹配的子組。如果沒有匹配,則彈出一項(匹配型別)並推送 None

在 3.11 版本中新增。

WITH_EXCEPT_START

呼叫堆疊位置 4 中的函式,其引數 (type, val, tb) 表示堆疊頂部的異常。用於實現當 with 語句中發生異常時呼叫 context_manager.__exit__(*exc_info())

在 3.9 版本中加入。

在 3.11 版本中更改: __exit__ 函式位於堆疊的位置 4,而不是位置 7。堆疊上的異常表示現在由一項組成,而不是三項。

LOAD_ASSERTION_ERROR

AssertionError 推送到堆疊上。由 assert 語句使用。

在 3.9 版本中加入。

LOAD_BUILD_CLASS

builtins.__build_class__() 推送到堆疊上。稍後將呼叫它來構造一個類。

BEFORE_WITH

此操作碼在 with 程式碼塊開始之前執行多個操作。首先,它從上下文管理器中載入 __exit__(),並將其推送到堆疊上,供 WITH_EXCEPT_START 稍後使用。然後,呼叫 __enter__()。最後,將呼叫 __enter__() 方法的結果推送到堆疊上。

在 3.11 版本中新增。

GET_LEN

執行 STACK.append(len(STACK[-1]))。在需要與模式結構進行比較的 match 語句中使用。

在 3.10 版本中加入。

MATCH_MAPPING

如果 STACK[-1]collections.abc.Mapping 的例項(或者,更準確地說:如果其 tp_flags 中設定了 Py_TPFLAGS_MAPPING 標誌),則將 True 推送到堆疊上。否則,推送 False

在 3.10 版本中加入。

MATCH_SEQUENCE

如果 STACK[-1]collections.abc.Sequence 的例項,並且不是 str/bytes/bytearray 的例項(或者,更準確地說:如果其 tp_flags 中設定了 Py_TPFLAGS_SEQUENCE 標誌),則將 True 推送到堆疊上。否則,推送 False

在 3.10 版本中加入。

MATCH_KEYS

STACK[-1] 是對映鍵的元組,STACK[-2] 是匹配主體。如果 STACK[-2] 包含 STACK[-1] 中的所有鍵,則推送一個包含相應值的 tuple。否則,推送 None

在 3.10 版本中加入。

在 3.11 版本中更改:以前,此指令還會推送一個布林值,指示成功 (True) 或失敗 (False)。

STORE_NAME(namei)

實現 name = STACK.pop()nameico_names 屬性中 name 的索引,該屬性是程式碼物件。編譯器會嘗試儘可能使用 STORE_FASTSTORE_GLOBAL

DELETE_NAME(namei)

實現 del name,其中 nameico_names 屬性的索引,該屬性是程式碼物件

UNPACK_SEQUENCE(count)

STACK[-1] 解包為 count 個單獨的值,這些值從右到左放入堆疊。要求必須恰好有 count 個值。

assert(len(STACK[-1]) == count)
STACK.extend(STACK.pop()[:-count-1:-1])
UNPACK_EX(counts)

使用帶星號的目標實現賦值:將 STACK[-1] 中的可迭代物件解包為單獨的值,其中值的總數可以小於可迭代物件中的項數:其中一個新值將是所有剩餘項的列表。

列表值之前和之後的值的數量限制為 255。

列表值之前的數值個數編碼在操作碼的引數中。列表之後的數值個數(如果有)使用 EXTENDED_ARG 進行編碼。因此,該引數可以被視為一個兩位元組的值,其中 counts 的低位元組表示列表值之前的數值個數,counts 的高位元組表示列表值之後的數值個數。

提取的值會以從右到左的順序放入堆疊,即 a, *b, c = d 在執行後將儲存為 STACK.extend((a, b, c))

STORE_ATTR(namei)

實現

obj = STACK.pop()
value = STACK.pop()
obj.name = value

其中 nameico_names 中名稱的索引,此 程式碼物件 的屬性。

DELETE_ATTR(namei)

實現

obj = STACK.pop()
del obj.name

其中 nameico_names 中名稱的索引,此 程式碼物件 的屬性。

STORE_GLOBAL(namei)

STORE_NAME 的工作方式相同,但將名稱儲存為全域性名稱。

DELETE_GLOBAL(namei)

DELETE_NAME 的工作方式相同,但刪除全域性名稱。

LOAD_CONST(consti)

co_consts[consti] 壓入堆疊。

LOAD_NAME(namei)

將與 co_names[namei] 關聯的值壓入堆疊。該名稱首先在區域性變數中查詢,然後在全域性變數中查詢,最後在內建變數中查詢。

LOAD_LOCALS

將對區域性變數字典的引用壓入堆疊。這用於為 LOAD_FROM_DICT_OR_DEREFLOAD_FROM_DICT_OR_GLOBALS 準備名稱空間字典。

在 3.12 版本中新增。

LOAD_FROM_DICT_OR_GLOBALS(i)

從堆疊中彈出一個對映,並查詢 co_names[namei] 的值。如果在那裡找不到該名稱,則會在全域性變數中查詢,然後再在內建變數中查詢,類似於 LOAD_GLOBAL。這用於在類主體內的 註釋作用域 中載入全域性變數。

在 3.12 版本中新增。

BUILD_TUPLE(count)

建立一個元組,從堆疊中消耗 count 個項,並將結果元組壓入堆疊

if count == 0:
    value = ()
else:
    value = tuple(STACK[-count:])
    STACK = STACK[:-count]

STACK.append(value)
BUILD_LIST(count)

BUILD_TUPLE 的工作方式相同,但建立一個列表。

BUILD_SET(count)

BUILD_TUPLE 的工作方式相同,但建立一個集合。

BUILD_MAP(count)

將一個新的字典物件壓入堆疊。彈出 2 * count 個項,以便字典包含 count 個條目:{..., STACK[-4]: STACK[-3], STACK[-2]: STACK[-1]}

3.5 版本更改: 該字典是從堆疊項建立的,而不是建立一個預先調整大小以容納 count 個項的空字典。

BUILD_CONST_KEY_MAP(count)

BUILD_MAP 的專門用於常量鍵的版本。彈出堆疊頂部的元素,該元素包含一個鍵的元組,然後從 STACK[-2] 開始,彈出 count 個值以形成構建的字典中的值。

在 3.6 版本中加入。

BUILD_STRING(count)

從堆疊中連線 count 個字串,並將結果字串壓入堆疊。

在 3.6 版本中加入。

LIST_EXTEND(i)

實現

seq = STACK.pop()
list.extend(STACK[-i], seq)

用於構建列表。

在 3.9 版本中加入。

SET_UPDATE(i)

實現

seq = STACK.pop()
set.update(STACK[-i], seq)

用於構建集合。

在 3.9 版本中加入。

DICT_UPDATE(i)

實現

map = STACK.pop()
dict.update(STACK[-i], map)

用於構建字典。

在 3.9 版本中加入。

DICT_MERGE(i)

DICT_UPDATE 類似,但對於重複的鍵會引發異常。

在 3.9 版本中加入。

LOAD_ATTR(namei)

如果 namei 的低位未設定,則此操作會將 STACK[-1] 替換為 getattr(STACK[-1], co_names[namei>>1])

如果 namei 的低位已設定,則將嘗試從 STACK[-1] 物件載入名為 co_names[namei>>1] 的方法。彈出 STACK[-1]。此位元組碼區分兩種情況:如果 STACK[-1] 具有正確名稱的方法,則位元組碼將壓入未繫結方法和 STACK[-1]。當呼叫未繫結方法時,STACK[-1] 將被用作 CALLCALL_KW 的第一個引數(self)。否則,將壓入 NULL 和屬性查詢返回的物件。

3.12 版本更改: 如果 namei 的低位已設定,則在屬性或未繫結方法之前,將 NULLself 壓入堆疊。

LOAD_SUPER_ATTR(namei)

此操作碼實現 super(),包括其零引數形式和雙引數形式(例如,super().method()super().attrsuper(cls, self).method()super(cls, self).attr)。

它從堆疊中彈出三個值(從堆疊頂部向下):

  • self: 當前方法的第一個引數

  • cls: 定義當前方法的類

  • 全域性變數 super

關於它的引數,它的工作方式類似於 LOAD_ATTR,除了 namei 向左移動 2 位而不是 1 位。

namei 的低位表示嘗試載入方法,就像 LOAD_ATTR 一樣,這會導致壓入 NULL 和載入的方法。如果未設定,則將單個值壓入堆疊。

如果設定了 namei 的第二低位,則表示這是對 super() 的雙引數呼叫(未設定表示零引數呼叫)。

在 3.12 版本中新增。

COMPARE_OP(opname)

執行布林運算。 運算名稱可以在 cmp_op[opname >> 5] 中找到。 如果設定了 opname 的第五低位 (opname & 16),則結果應強制轉換為 bool

在 3.13 版本中變更:現在,運算元的第五低位表示強制轉換為 bool

IS_OP(invert)

執行 is 比較,如果 invert 為 1,則執行 is not 比較。

在 3.9 版本中加入。

CONTAINS_OP(invert)

執行 in 比較,如果 invert 為 1,則執行 not in 比較。

在 3.9 版本中加入。

IMPORT_NAME(namei)

匯入模組 co_names[namei]STACK[-1]STACK[-2] 被彈出,並提供 __import__() 的 *fromlist* 和 *level* 引數。模組物件被壓入堆疊。當前名稱空間不受影響:對於正確的匯入語句,後續的 STORE_FAST 指令會修改名稱空間。

IMPORT_FROM(namei)

STACK[-1] 中找到的模組載入屬性 co_names[namei]。 結果物件被壓入堆疊,隨後由 STORE_FAST 指令儲存。

JUMP_FORWARD(delta)

將位元組碼計數器增加 *delta*。

JUMP_BACKWARD(delta)

將位元組碼計數器減少 *delta*。檢查中斷。

在 3.11 版本中新增。

JUMP_BACKWARD_NO_INTERRUPT(delta)

將位元組碼計數器減少 *delta*。不檢查中斷。

在 3.11 版本中新增。

POP_JUMP_IF_TRUE(delta)

如果 STACK[-1] 為 true,則將位元組碼計數器增加 *delta*。STACK[-1] 被彈出。

在 3.11 版本中變更:運算元現在是一個相對增量,而不是絕對目標。此操作碼是一個偽指令,在最終位元組碼中被定向版本(向前/向後)替換。

在 3.12 版本中變更:這不再是偽指令。

在 3.13 版本中更改: 此指令現在要求一個精確的 bool 運算元。

POP_JUMP_IF_FALSE(delta)

如果 STACK[-1] 為 false,則將位元組碼計數器增加 *delta*。STACK[-1] 被彈出。

在 3.11 版本中變更:運算元現在是一個相對增量,而不是絕對目標。此操作碼是一個偽指令,在最終位元組碼中被定向版本(向前/向後)替換。

在 3.12 版本中變更:這不再是偽指令。

在 3.13 版本中更改: 此指令現在要求一個精確的 bool 運算元。

POP_JUMP_IF_NOT_NONE(delta)

如果 STACK[-1] 不是 None,則將位元組碼計數器增加 *delta*。STACK[-1] 被彈出。

此操作碼是一個偽指令,在最終位元組碼中被定向版本(向前/向後)替換。

在 3.11 版本中新增。

在 3.12 版本中變更:這不再是偽指令。

POP_JUMP_IF_NONE(delta)

如果 STACK[-1]None,則將位元組碼計數器增加 *delta*。STACK[-1] 被彈出。

此操作碼是一個偽指令,在最終位元組碼中被定向版本(向前/向後)替換。

在 3.11 版本中新增。

在 3.12 版本中變更:這不再是偽指令。

FOR_ITER(delta)

STACK[-1] 是一個 迭代器。呼叫其 __next__() 方法。如果這產生一個新值,則將其壓入堆疊(將迭代器留在其下方)。如果迭代器指示它已耗盡,則將位元組碼計數器增加 *delta*。

在 3.12 版本中變更:在 3.11 版本之前,迭代器在耗盡時會被彈出。

LOAD_GLOBAL(namei)

將名為 co_names[namei>>1] 的全域性變數載入到堆疊上。

在 3.11 版本中變更:如果設定了 namei 的低位,則在全域性變數之前將 NULL 推入堆疊。

LOAD_FAST(var_num)

將對區域性變數 co_varnames[var_num] 的引用推入堆疊。

在 3.12 版本中變更:此操作碼現在僅用於保證區域性變數已初始化的情形。它不能引發 UnboundLocalError

LOAD_FAST_LOAD_FAST(var_nums)

將對 co_varnames[var_nums >> 4]co_varnames[var_nums & 15] 的引用推入堆疊。

在 3.13 版本中新增。

LOAD_FAST_CHECK(var_num)

將對區域性變數 co_varnames[var_num] 的引用推入堆疊,如果區域性變數未初始化,則引發 UnboundLocalError

在 3.12 版本中新增。

LOAD_FAST_AND_CLEAR(var_num)

將對區域性變數 co_varnames[var_num] 的引用推入堆疊(如果區域性變數未初始化,則將 NULL 推入堆疊),並將 co_varnames[var_num] 設定為 NULL

在 3.12 版本中新增。

STORE_FAST(var_num)

STACK.pop() 儲存到區域性變數 co_varnames[var_num] 中。

STORE_FAST_STORE_FAST(var_nums)

STACK[-1] 儲存到 co_varnames[var_nums >> 4] 中,並將 STACK[-2] 儲存到 co_varnames[var_nums & 15] 中。

在 3.13 版本中新增。

STORE_FAST_LOAD_FAST(var_nums)

STACK.pop() 儲存到區域性變數 co_varnames[var_nums >> 4] 中,並將對區域性變數 co_varnames[var_nums & 15] 的引用推入堆疊。

在 3.13 版本中新增。

DELETE_FAST(var_num)

刪除區域性變數 co_varnames[var_num]

MAKE_CELL(i)

在槽位 i 中建立一個新單元格。如果該槽位非空,則將該值儲存到新單元格中。

在 3.11 版本中新增。

LOAD_DEREF(i)

載入“快速區域性變數”儲存區槽位 i 中包含的單元格。將單元格中包含的物件的引用推送到堆疊上。

在 3.11 版本中更改: i 不再被 co_varnames 的長度偏移。

LOAD_FROM_DICT_OR_DEREF(i)

從堆疊中彈出一個對映,並在該對映中查詢與“快速區域性變數”儲存區槽位 i 關聯的名稱。如果該名稱未在此處找到,則從槽位 i 中包含的單元格載入,類似於 LOAD_DEREF。這用於在類主體中(之前使用 LOAD_CLASSDEREF)和類主體內的註解作用域中載入閉包變數

在 3.12 版本中新增。

STORE_DEREF(i)

STACK.pop() 儲存到“快速區域性變數”儲存區槽位 i 中包含的單元格中。

在 3.11 版本中更改: i 不再被 co_varnames 的長度偏移。

DELETE_DEREF(i)

清空“快速區域性變數”儲存區槽位 i 中包含的單元格。由 del 語句使用。

3.2 版本新增。

在 3.11 版本中更改: i 不再被 co_varnames 的長度偏移。

COPY_FREE_VARS(n)

n自由(閉包)變數從閉包複製到幀中。消除了在呼叫閉包時需要在呼叫方進行特殊程式碼的需求。

在 3.11 版本中新增。

RAISE_VARARGS(argc)

根據 argc 的值,使用 raise 語句的 3 種形式之一引發異常

  • 0: raise(重新引發先前的異常)

  • 1: raise STACK[-1](在 STACK[-1] 處引發異常例項或型別)

  • 2: raise STACK[-2] from STACK[-1](在 STACK[-2] 處引發異常例項或型別,並將 __cause__ 設定為 STACK[-1]

CALL(argc)

使用 argc 指定的引數數量呼叫可呼叫物件。堆疊上的內容(按升序排列)為:

  • 可呼叫物件

  • selfNULL

  • 其餘的位置引數

argc 是位置引數的總數,不包括 self

CALL 會將所有引數和可呼叫物件從堆疊中彈出,使用這些引數呼叫可呼叫物件,並將可呼叫物件返回的返回值推送到堆疊上。

在 3.11 版本中新增。

在 3.13 版本中更改: 可呼叫物件現在始終出現在堆疊上的相同位置。

在 3.13 版本中更改: 帶有關鍵字引數的呼叫現在由 CALL_KW 處理。

CALL_KW(argc)

使用 argc 指定的引數數量(包括一個或多個命名引數)呼叫可呼叫物件。堆疊上的內容(按升序排列)為:

  • 可呼叫物件

  • selfNULL

  • 其餘的位置引數

  • 命名引數

  • 關鍵字引數名稱的 tuple

argc 是位置引數和命名引數的總數,不包括 self。關鍵字引數名稱的元組的長度是命名引數的數量。

CALL_KW 會將所有引數、關鍵字名稱和可呼叫物件從堆疊中彈出,使用這些引數呼叫可呼叫物件,並將可呼叫物件返回的返回值推送到堆疊上。

在 3.13 版本中新增。

CALL_FUNCTION_EX(flags)

使用可變的一組位置引數和關鍵字引數呼叫可呼叫物件。如果 flags 的最低位已設定,則堆疊的頂部包含一個對映物件,其中包含其他關鍵字引數。在呼叫可呼叫物件之前,對映物件和可迭代物件都會被“解包”,它們的內容分別作為關鍵字引數和位置引數傳遞。 CALL_FUNCTION_EX 會將所有引數和可呼叫物件從堆疊中彈出,使用這些引數呼叫可呼叫物件,並將可呼叫物件返回的返回值推送到堆疊上。

在 3.6 版本中加入。

PUSH_NULL

NULL 推送到堆疊。在呼叫序列中用於匹配 LOAD_METHOD 為非方法呼叫推送的 NULL

在 3.11 版本中新增。

MAKE_FUNCTION

在堆疊上推送從 STACK[-1] 處的程式碼物件構建的新函式物件。

在 3.10 版本中更改: 標誌值 0x04 是字串元組而不是字典

在 3.11 版本中更改: 刪除了 STACK[-1] 處的限定名稱。

在 3.13 版本中更改: 刪除了堆疊上的額外函式屬性,這些屬性由操作碼標誌發出訊號。它們現在使用 SET_FUNCTION_ATTRIBUTE

SET_FUNCTION_ATTRIBUTE(flag)

在函式物件上設定屬性。 預期 STACK[-1] 處的函式和要在 STACK[-2] 處設定的屬性值;消耗兩者,並在 STACK[-1] 處保留函式。該標誌確定要設定哪個屬性

  • 0x01 按位置順序排列的僅限位置和位置或關鍵字引數的預設值元組

  • 0x02 僅限關鍵字引數的預設值的字典

  • 0x04 包含引數註釋的字串元組

  • 0x08 包含自由變數單元格的元組,構成一個閉包

在 3.13 版本中新增。

BUILD_SLICE(argc)

在堆疊上推送一個切片物件。argc 必須為 2 或 3。如果為 2,則實現

end = STACK.pop()
start = STACK.pop()
STACK.append(slice(start, end))

如果為 3,則實現

step = STACK.pop()
end = STACK.pop()
start = STACK.pop()
STACK.append(slice(start, end, step))

有關更多資訊,請參閱 slice() 內建函式。

EXTENDED_ARG(ext)

為任何引數太大而無法放入預設的一個位元組的操作碼新增字首。ext 儲存一個額外的位元組,該位元組充當引數中的高位。對於每個操作碼,最多允許三個字首 EXTENDED_ARG,從而形成從兩位元組到四位元組的引數。

CONVERT_VALUE(oparg)

根據 oparg 將值轉換為字串

value = STACK.pop()
result = func(value)
STACK.append(result)
  • oparg == 1:在 value 上呼叫 str()

  • oparg == 2:在 value 上呼叫 repr()

  • oparg == 3:在 value 上呼叫 ascii()

用於實現格式化的文字字串(f-字串)。

在 3.13 版本中新增。

FORMAT_SIMPLE

格式化堆疊頂部的值

value = STACK.pop()
result = value.__format__("")
STACK.append(result)

用於實現格式化的文字字串(f-字串)。

在 3.13 版本中新增。

FORMAT_WITH_SPEC

使用給定的格式規範格式化給定值

spec = STACK.pop()
value = STACK.pop()
result = value.__format__(spec)
STACK.append(result)

用於實現格式化的文字字串(f-字串)。

在 3.13 版本中新增。

MATCH_CLASS(count)

STACK[-1] 是關鍵字屬性名稱的元組,STACK[-2] 是要匹配的類,而 STACK[-3] 是匹配的主題。count 是位置子模式的數量。

彈出 STACK[-1]STACK[-2]STACK[-3]。如果 STACK[-3]STACK[-2] 的例項,並且具有 countSTACK[-1] 所要求的位置屬性和關鍵字屬性,則壓入一個提取的屬性元組。否則,壓入 None

在 3.10 版本中加入。

在 3.11 版本中更改:以前,此指令還會推送一個布林值,指示成功 (True) 或失敗 (False)。

RESUME(context)

空操作。執行內部跟蹤、除錯和最佳化檢查。

context 運算元由兩部分組成。最低兩位表示 RESUME 發生的位置

  • 0 函式的開始,既不是生成器、協程也不是非同步生成器

  • 1yield 表示式之後

  • 2yield from 表示式之後

  • 3await 表示式之後

如果 RESUME 處於 except-depth 1,則下一位為 1,否則為 0

在 3.11 版本中新增。

在 3.13 版本中更改: oparg 值已更改,以包含有關 except-depth 的資訊

RETURN_GENERATOR

從當前幀建立一個生成器、協程或非同步生成器。用作上述可呼叫物件的程式碼物件中的第一個操作碼。清除當前幀並返回新建立的生成器。

在 3.11 版本中新增。

SEND(delta)

等效於 STACK[-1] = STACK[-2].send(STACK[-1])。用於 yield fromawait 語句中。

如果呼叫引發 StopIteration,則從堆疊中彈出頂部值,壓入異常的 value 屬性,並將位元組碼計數器增加 delta

在 3.11 版本中新增。

HAVE_ARGUMENT

這實際上不是一個操作碼。它標識了範圍 [0,255] 中不使用其引數的操作碼和使用其引數的操作碼(分別為 < HAVE_ARGUMENT>= HAVE_ARGUMENT)之間的分界線。

如果你的應用程式使用偽指令或專用指令,請改用 hasarg 集合。

在 3.6 版本中更改: 現在每個指令都有一個引數,但操作碼 < HAVE_ARGUMENT 會忽略它。之前,只有操作碼 >= HAVE_ARGUMENT 有一個引數。

在 3.12 版本中更改: 偽指令已新增到 dis 模組中,對於它們來說,與 HAVE_ARGUMENT 的比較並不表示它們是否使用其引數。

自 3.13 版本起已棄用: 請改用 hasarg

CALL_INTRINSIC_1

呼叫一個帶有一個引數的內部函式。將 STACK[-1] 作為引數傳遞,並將 STACK[-1] 設定為結果。用於實現非效能關鍵的功能。

運算元決定呼叫哪個內部函式

運算元

描述

INTRINSIC_1_INVALID

無效

INTRINSIC_PRINT

將引數列印到標準輸出。在 REPL 中使用。

INTRINSIC_IMPORT_STAR

對命名模組執行 import *

INTRINSIC_STOPITERATION_ERROR

StopIteration 異常中提取返回值。

INTRINSIC_ASYNC_GEN_WRAP

包裝一個非同步生成器值

INTRINSIC_UNARY_POSITIVE

執行一元 + 運算

INTRINSIC_LIST_TO_TUPLE

將列表轉換為元組

INTRINSIC_TYPEVAR

建立一個 typing.TypeVar

INTRINSIC_PARAMSPEC

建立一個 typing.ParamSpec

INTRINSIC_TYPEVARTUPLE

建立一個 typing.TypeVarTuple

INTRINSIC_SUBSCRIPT_GENERIC

返回以引數下標的 typing.Generic

INTRINSIC_TYPEALIAS

建立一個 typing.TypeAliasType;在 type 語句中使用。引數是類型別名的名稱、型別引數和值的元組。

在 3.12 版本中新增。

CALL_INTRINSIC_2

呼叫一個帶有兩個引數的內部函式。用於實現非效能關鍵的功能

arg2 = STACK.pop()
arg1 = STACK.pop()
result = intrinsic2(arg1, arg2)
STACK.append(result)

運算元決定呼叫哪個內部函式

運算元

描述

INTRINSIC_2_INVALID

無效

INTRINSIC_PREP_RERAISE_STAR

計算從 try-except* 引發的 ExceptionGroup

INTRINSIC_TYPEVAR_WITH_BOUND

建立一個帶有邊界的 typing.TypeVar

INTRINSIC_TYPEVAR_WITH_CONSTRAINTS

建立一個帶有約束的 typing.TypeVar

INTRINSIC_SET_FUNCTION_TYPE_PARAMS

設定函式的 __type_params__ 屬性。

在 3.12 版本中新增。

偽指令

這些操作碼不會出現在 Python 位元組碼中。它們由編譯器使用,但在生成位元組碼之前會被真實的操作碼替換或刪除。

SETUP_FINALLY(target)

為以下程式碼塊設定異常處理程式。如果發生異常,則將值堆疊級別恢復到其當前狀態,並將控制權轉移到 target 處的異常處理程式。

SETUP_CLEANUP(target)

類似於 SETUP_FINALLY,但如果發生異常,還會將最後一條指令(lasti)壓入堆疊,以便 RERAISE 可以恢復它。如果發生異常,則將值堆疊級別和幀上的最後一條指令恢復到其當前狀態,並將控制權轉移到 target 處的異常處理程式。

SETUP_WITH(target)

類似於 SETUP_CLEANUP,但如果發生異常,則在將控制權轉移到 target 處的異常處理程式之前,還會從堆疊中彈出一個專案。

此變體用於 withasync with 構造中,它們將上下文管理器的 __enter__()__aenter__() 的返回值壓入堆疊。

POP_BLOCK

標記與最後一個 SETUP_FINALLYSETUP_CLEANUPSETUP_WITH 關聯的程式碼塊的結束。

JUMP
JUMP_NO_INTERRUPT

無方向的相對跳轉指令,由彙編器替換為其有方向(向前/向後)的對應指令。

LOAD_CLOSURE(i)

將對“快速區域性變數”儲存中槽 i 中包含的單元格的引用壓入堆疊。

請注意,LOAD_CLOSURE 在彙編器中被替換為 LOAD_FAST

在 3.13 版本中更改: 此操作碼現在是一個偽指令。

LOAD_METHOD

最佳化的未繫結方法查詢。作為設定了引數標誌的 LOAD_ATTR 操作碼發出。

操作碼集合

這些集合用於自動內省位元組碼指令

在 3.12 版本中更改: 這些集合現在也包含偽指令和檢測指令。這些是值 >= MIN_PSEUDO_OPCODE>= MIN_INSTRUMENTED_OPCODE 的操作碼。

dis.opname

操作名稱序列,可使用位元組碼進行索引。

dis.opmap

將操作名稱對映到位元組碼的字典。

dis.cmp_op

所有比較操作名稱的序列。

dis.hasarg

使用其引數的位元組碼序列。

在 3.12 版本中新增。

dis.hasconst

訪問常量的位元組碼序列。

dis.hasfree

訪問自由(閉包)變數的位元組碼序列。此上下文中的“自由”是指當前作用域中被內部作用域引用的名稱,或從此作用域引用的外部作用域中的名稱。它包括對全域性或內建作用域的引用。

dis.hasname

按名稱訪問屬性的位元組碼序列。

dis.hasjump

具有跳轉目標的位元組碼序列。所有跳轉都是相對的。

在 3.13 版本中新增。

dis.haslocal

訪問區域性變數的位元組碼序列。

dis.hascompare

布林運算的位元組碼序列。

dis.hasexc

設定異常處理程式的位元組碼序列。

在 3.12 版本中新增。

dis.hasjrel

具有相對跳轉目標的位元組碼序列。

自 3.13 版本起已棄用: 所有跳轉現在都是相對的。請使用 hasjump

dis.hasjabs

具有絕對跳轉目標的位元組碼序列。

自 3.13 版本起已棄用: 所有跳轉現在都是相對的。此列表為空。