python指令集_Python 2.6.2的字节码指令集一览

对Python的字节码指令集感兴趣但不知道从何下手么?执行这段代码就能看到字节码的列表:

Python代码

import opcode

for op in range(len(opcode.opname)):

print('0x%.2X(%.3d): %s' % (op, op, opcode.opname[op]))

在Python 2.6.2上运行的输出结果:

(格式:操作码的十六进制(十进制): 操作码的助记名)

Python opcode list代码

0x00(000): STOP_CODE

0x01(001): POP_TOP

0x02(002): ROT_TWO

0x03(003): ROT_THREE

0x04(004): DUP_TOP

0x05(005): ROT_FOUR

0x06(006): <6>

0x07(007): <7>

0x08(008): <8>

0x09(009): NOP

0x0A(010): UNARY_POSITIVE

0x0B(011): UNARY_NEGATIVE

0x0C(012): UNARY_NOT

0x0D(013): UNARY_CONVERT

0x0E(014): <14>

0x0F(015): UNARY_INVERT

0x10(016): <16>

0x11(017): <17>

0x12(018): LIST_APPEND

0x13(019): BINARY_POWER

0x14(020): BINARY_MULTIPLY

0x15(021): BINARY_DIVIDE

0x16(022): BINARY_MODULO

0x17(023): BINARY_ADD

0x18(024): BINARY_SUBTRACT

0x19(025): BINARY_SUBSCR

0x1A(026): BINARY_FLOOR_DIVIDE

0x1B(027): BINARY_TRUE_DIVIDE

0x1C(028): INPLACE_FLOOR_DIVIDE

0x1D(029): INPLACE_TRUE_DIVIDE

0x1E(030): SLICE+0

0x1F(031): SLICE+1

0x20(032): SLICE+2

0x21(033): SLICE+3

0x22(034): <34>

0x23(035): <35>

0x24(036): <36>

0x25(037): <37>

0x26(038): <38>

0x27(039): <39>

0x28(040): STORE_SLICE+0

0x29(041): STORE_SLICE+1

0x2A(042): STORE_SLICE+2

0x2B(043): STORE_SLICE+3

0x2C(044): <44>

0x2D(045): <45>

0x2E(046): <46>

0x2F(047): <47>

0x30(048): <48>

0x31(049): <49>

0x32(050): DELETE_SLICE+0

0x33(051): DELETE_SLICE+1

0x34(052): DELETE_SLICE+2

0x35(053): DELETE_SLICE+3

0x36(054): STORE_MAP

0x37(055): INPLACE_ADD

0x38(056): INPLACE_SUBTRACT

0x39(057): INPLACE_MULTIPLY

0x3A(058): INPLACE_DIVIDE

0x3B(059): INPLACE_MODULO

0x3C(060): STORE_SUBSCR

0x3D(061): DELETE_SUBSCR

0x3E(062): BINARY_LSHIFT

0x3F(063): BINARY_RSHIFT

0x40(064): BINARY_AND

0x41(065): BINARY_XOR

0x42(066): BINARY_OR

0x43(067): INPLACE_POWER

0x44(068): GET_ITER

0x45(069): <69>

0x46(070): PRINT_EXPR

0x47(071): PRINT_ITEM

0x48(072): PRINT_NEWLINE

0x49(073): PRINT_ITEM_TO

0x4A(074): PRINT_NEWLINE_TO

0x4B(075): INPLACE_LSHIFT

0x4C(076): INPLACE_RSHIFT

0x4D(077): INPLACE_AND

0x4E(078): INPLACE_XOR

0x4F(079): INPLACE_OR

0x50(080): BREAK_LOOP

0x51(081): WITH_CLEANUP

0x52(082): LOAD_LOCALS

0x53(083): RETURN_VALUE

0x54(084): IMPORT_STAR

0x55(085): EXEC_STMT

0x56(086): YIELD_VALUE

0x57(087): POP_BLOCK

0x58(088): END_FINALLY

0x59(089): BUILD_CLASS

0x5A(090): STORE_NAME

0x5B(091): DELETE_NAME

0x5C(092): UNPACK_SEQUENCE

0x5D(093): FOR_ITER

0x5E(094): <94>

0x5F(095): STORE_ATTR

0x60(096): DELETE_ATTR

0x61(097): STORE_GLOBAL

0x62(098): DELETE_GLOBAL

0x63(099): DUP_TOPX

0x64(100): LOAD_CONST

0x65(101): LOAD_NAME

0x66(102): BUILD_TUPLE

0x67(103): BUILD_LIST

0x68(104): BUILD_MAP

0x69(105): LOAD_ATTR

0x6A(106): COMPARE_OP

0x6B(107): IMPORT_NAME

0x6C(108): IMPORT_FROM

0x6D(109): <109>

0x6E(110): JUMP_FORWARD

0x6F(111): JUMP_IF_FALSE

0x70(112): JUMP_IF_TRUE

0x71(113): JUMP_ABSOLUTE

0x72(114): <114>

0x73(115): <115>

0x74(116): LOAD_GLOBAL

0x75(117): <117>

0x76(118): <118>

0x77(119): CONTINUE_LOOP

0x78(120): SETUP_LOOP

0x79(121): SETUP_EXCEPT

0x7A(122): SETUP_FINALLY

0x7B(123): <123>

0x7C(124): LOAD_FAST

0x7D(125): STORE_FAST

0x7E(126): DELETE_FAST

0x7F(127): <127>

0x80(128): <128>

0x81(129): <129>

0x82(130): RAISE_VARARGS

0x83(131): CALL_FUNCTION

0x84(132): MAKE_FUNCTION

0x85(133): BUILD_SLICE

0x86(134): MAKE_CLOSURE

0x87(135): LOAD_CLOSURE

0x88(136): LOAD_DEREF

0x89(137): STORE_DEREF

0x8A(138): <138>

0x8B(139): <139>

0x8C(140): CALL_FUNCTION_VAR

0x8D(141): CALL_FUNCTION_KW

0x8E(142): CALL_FUNCTION_VAR_KW

0x8F(143): EXTENDED_ARG

0x90(144): <144>

0x91(145): <145>

0x92(146): <146>

0x93(147): <147>

0x94(148): <148>

0x95(149): <149>

0x96(150): <150>

0x97(151): <151>

0x98(152): <152>

0x99(153): <153>

0x9A(154): <154>

0x9B(155): <155>

0x9C(156): <156>

0x9D(157): <157>

0x9E(158): <158>

0x9F(159): <159>

0xA0(160): <160>

0xA1(161): <161>

0xA2(162): <162>

0xA3(163): <163>

0xA4(164): <164>

0xA5(165): <165>

0xA6(166): <166>

0xA7(167): <167>

0xA8(168): <168>

0xA9(169): <169>

0xAA(170): <170>

0xAB(171): <171>

0xAC(172): <172>

0xAD(173): <173>

0xAE(174): <174>

0xAF(175): <175>

0xB0(176): <176>

0xB1(177): <177>

0xB2(178): <178>

0xB3(179): <179>

0xB4(180): <180>

0xB5(181): <181>

0xB6(182): <182>

0xB7(183): <183>

0xB8(184): <184>

0xB9(185): <185>

0xBA(186): <186>

0xBB(187): <187>

0xBC(188): <188>

0xBD(189): <189>

0xBE(190): <190>

0xBF(191): <191>

0xC0(192): <192>

0xC1(193): <193>

0xC2(194): <194>

0xC3(195): <195>

0xC4(196): <196>

0xC5(197): <197>

0xC6(198): <198>

0xC7(199): <199>

0xC8(200): <200>

0xC9(201): <201>

0xCA(202): <202>

0xCB(203): <203>

0xCC(204): <204>

0xCD(205): <205>

0xCE(206): <206>

0xCF(207): <207>

0xD0(208): <208>

0xD1(209): <209>

0xD2(210): <210>

0xD3(211): <211>

0xD4(212): <212>

0xD5(213): <213>

0xD6(214): <214>

0xD7(215): <215>

0xD8(216): <216>

0xD9(217): <217>

0xDA(218): <218>

0xDB(219): <219>

0xDC(220): <220>

0xDD(221): <221>

0xDE(222): <222>

0xDF(223): <223>

0xE0(224): <224>

0xE1(225): <225>

0xE2(226): <226>

0xE3(227): <227>

0xE4(228): <228>

0xE5(229): <229>

0xE6(230): <230>

0xE7(231): <231>

0xE8(232): <232>

0xE9(233): <233>

0xEA(234): <234>

0xEB(235): <235>

0xEC(236): <236>

0xED(237): <237>

0xEE(238): <238>

0xEF(239): <239>

0xF0(240): <240>

0xF1(241): <241>

0xF2(242): <242>

0xF3(243): <243>

0xF4(244): <244>

0xF5(245): <245>

0xF6(246): <246>

0xF7(247): <247>

0xF8(248): <248>

0xF9(249): <249>

0xFA(250): <250>

0xFB(251): <251>

0xFC(252): <252>

0xFD(253): <253>

0xFE(254): <254>

0xFF(255): <255>

助记名为“”形式的是未使用的操作码。

既然叫“字节码”,这些操作码自然是以字节为单位的咯,于是最多只能表示256个不同的操作码。Python实际上只用了百来个操作码。

操作码小于90的为无参数的,指令仅包含操作码自身,共1字节;大于等于90的,则每条指令在操作码之后还带有1个参数,参数长度为2字节,共3字节。

Python程序的字节码在运行时以PyStringObject的形式保存在PyCodeObject的co_code域里。co_code域只含有指令而不包含别的程序数据;变量名、常量等数据均放在别的域里。

Python的字节码指令集是基于栈的指令集。这里说的“栈”不是指函数调用栈,而是指专门用于求值的栈,可以称为“求值栈”(uation

stack)或者“操作数栈”(operand stack)。求值过程的临时变量都放在求值栈上,指令集中的大部分都是与栈打交道。

例如3 + 4会变成:

Python bytecode代码

LOAD_CONST 0 (3)

LOAT_CONST 1 (4)

BINARY_ADD

假设常量池中下标为0和1的项分别是3和4这两个常量,则头两条指令分别将这两个常量压入求值栈,然后BINARY_ADD指令将求值栈栈顶的两个值弹出,计算加法,并将结果再次压入栈中。理解了这点,则Python的指令集基本上都能顾名思义。操作码对应的具体意义可以在下面的官网文档链接查到。

但既然求值的参数和结果都放在求值栈上,那何必要带参数的指令呢?

关键区别就是,带参数的指令的参数都是一些由编译器指定的常量,例如指向常量池的下标、函数的参数个数、跳转指令的偏移量等。这些值不是Python对象,无法由程序员在源码中显式指定或操纵。

而求值栈上放的则是在源码中显式指定的一些参与计算的值,或者计算后的中间结果。这些值都是Python对象,其行为遵循Python类型系统的规定。

Python字节码中所有控制流指令都是带参数的,并且它们都不额外从求值栈取任何参数。这使得Python字节码程序的控制流在编译时就确定下来,或者说是可静态确定的。这样可以降低控制流被程序代码破坏的风险,也方便了解释器的实现。

python.org上关于Python字节码的详细介绍文档我只找到了一份,是对应Python 2.5.2的字节码列表。Python 2.6.2中大部分指令与这份文档中的相同,但有些细节不同,例如文档中说DUP_TOPX的参数范围是1-5,但在Python 2.6.2里实际上只允许2-3的范围。

在Python 3.x中字节码有了新的调整,至少PRINT_*系列的字节码都取消了。本帖开头的代码在Python 3.x上也可以运行,有兴趣的同学可以对比看看。

对Python字节码的解释方式感兴趣的同学,可以从c.c入手,观察Python虚拟机的核心——Py_FrameEx()的实现。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值