============================== 9.25 拆解Pythonå—节ç ============================== ---------- 问题 ---------- ä½ æƒ³é€šè¿‡å°†ä½ çš„ä»£ç å编译æˆä½Žçº§çš„å—èŠ‚ç æ¥æŸ¥çœ‹å®ƒåº•层的工作机制。 ---------- 解决方案 ---------- ``dis`` 模å—å¯ä»¥è¢«ç”¨æ¥è¾“出任何Python函数的å编译结果。例如: .. code-block:: python >>> def countdown(n): ... while n > 0: ... print('T-minus', n) ... n -= 1 ... print('Blastoff!') ... >>> import dis >>> dis.dis(countdown) 2 0 SETUP_LOOP 30 (to 32) >> 2 LOAD_FAST 0 (n) 4 LOAD_CONST 1 (0) 6 COMPARE_OP 4 (>) 8 POP_JUMP_IF_FALSE 30 3 10 LOAD_GLOBAL 0 (print) 12 LOAD_CONST 2 ('T-minus') 14 LOAD_FAST 0 (n) 16 CALL_FUNCTION 2 18 POP_TOP 4 20 LOAD_FAST 0 (n) 22 LOAD_CONST 3 (1) 24 INPLACE_SUBTRACT 26 STORE_FAST 0 (n) 28 JUMP_ABSOLUTE 2 >> 30 POP_BLOCK 5 >> 32 LOAD_GLOBAL 0 (print) 34 LOAD_CONST 4 ('Blastoff!') 36 CALL_FUNCTION 1 38 POP_TOP 40 LOAD_CONST 0 (None) 42 RETURN_VALUE >>> ---------- 讨论 ---------- å½“ä½ æƒ³è¦çŸ¥é“ä½ çš„ç¨‹åºåº•层的è¿è¡Œæœºåˆ¶çš„æ—¶å€™ï¼Œ``dis`` æ¨¡å—æ˜¯å¾ˆæœ‰ç”¨çš„ã€‚æ¯”å¦‚å¦‚æžœä½ æƒ³è¯•ç€ç†è§£æ€§èƒ½ç‰¹å¾ã€‚ 被 ``dis()`` 函数解æžçš„原始å—节ç 如下所示: .. code-block:: python >>> countdown.__code__.co_code b"x'\x00|\x00\x00d\x01\x00k\x04\x00r)\x00t\x00\x00d\x02\x00|\x00\x00\x83 \x02\x00\x01|\x00\x00d\x03\x008}\x00\x00q\x03\x00Wt\x00\x00d\x04\x00\x83 \x01\x00\x01d\x00\x00S" >>> å¦‚æžœä½ æƒ³è‡ªå·±è§£é‡Šè¿™æ®µä»£ç ï¼Œä½ éœ€è¦ä½¿ç”¨ä¸€äº›åœ¨ ``opcode`` 模å—ä¸å®šä¹‰çš„常é‡ã€‚例如: .. code-block:: python >>> c = countdown.__code__.co_code >>> import opcode >>> opcode.opname[c[0]] 'SETUP_LOOP' >>> opcode.opname[c[2]] 'LOAD_FAST' >>> 奇怪的是,在 ``dis`` 模å—ä¸å¹¶æ²¡æœ‰å‡½æ•°è®©ä½ 以编程方å¼å¾ˆå®¹æ˜“çš„æ¥å¤„ç†å—节ç 。 ä¸è¿‡ï¼Œä¸‹é¢çš„生æˆå™¨å‡½æ•°å¯ä»¥å°†åŽŸå§‹å—节ç åºåˆ—è½¬æ¢æˆ ``opcodes`` å’Œå‚æ•°ã€‚ .. code-block:: python import opcode def generate_opcodes(codebytes): extended_arg = 0 i = 0 n = len(codebytes) while i < n: op = codebytes[i] i += 1 if op >= opcode.HAVE_ARGUMENT: oparg = codebytes[i] + codebytes[i+1]*256 + extended_arg extended_arg = 0 i += 2 if op == opcode.EXTENDED_ARG: extended_arg = oparg * 65536 continue else: oparg = None yield (op, oparg) 使用方法如下: .. code-block:: python >>> for op, oparg in generate_opcodes(countdown.__code__.co_code): ... print(op, opcode.opname[op], oparg) è¿™ç§æ–¹å¼å¾ˆå°‘有人知é“ï¼Œä½ å¯ä»¥åˆ©ç”¨å®ƒæ›¿æ¢ä»»ä½•ä½ æƒ³è¦æ›¿æ¢çš„函数的原始å—节ç 。 䏋颿ˆ‘ä»¬ç”¨ä¸€ä¸ªç¤ºä¾‹æ¥æ¼”示整个过程: .. code-block:: python >>> def add(x, y): ... return x + y ... >>> c = add.__code__ >>> c <code object add at 0x1007beed0, file "<stdin>", line 1> >>> c.co_code b'|\x00\x00|\x01\x00\x17S' >>> >>> # Make a completely new code object with bogus byte code >>> import types >>> newbytecode = b'xxxxxxx' >>> nc = types.CodeType(c.co_argcount, c.co_kwonlyargcount, ... c.co_nlocals, c.co_stacksize, c.co_flags, newbytecode, c.co_consts, ... c.co_names, c.co_varnames, c.co_filename, c.co_name, ... c.co_firstlineno, c.co_lnotab) >>> nc <code object add at 0x10069fe40, file "<stdin>", line 1> >>> add.__code__ = nc >>> add(2,3) Segmentation fault ä½ å¯ä»¥åƒè¿™æ ·è€å¤§æ‹›è®©è§£é‡Šå™¨å¥”溃。但是,对于编写更高级优化和元编程工具的程åºå‘˜æ¥è®²ï¼Œ 他们å¯èƒ½çœŸçš„需è¦é‡å†™å—节ç 。本节最åŽçš„éƒ¨åˆ†æ¼”ç¤ºäº†è¿™ä¸ªæ˜¯æ€Žæ ·åšåˆ°çš„ã€‚ä½ è¿˜å¯ä»¥å‚考å¦å¤–一个类似的例å: `this code on ActiveState <http://code.activestate.com/recipes/277940-decorator-for-bindingconstants-at-compile-time/>`_