typedef struct { PyObject_HEAD int co_argcount; /* #arguments, except *args */ int co_kwonlyargcount; /* #keyword only arguments */ int co_nlocals; /* #local variables */ int co_stacksize; /* #entries needed for evaluation stack */ int co_flags; /* CO_..., see below */ PyObject *co_code; /* instruction opcodes */ PyObject *co_consts; /* list (constants used) */ PyObject *co_names; /* list of strings (names used) */ PyObject *co_varnames; /* tuple of strings (local variable names) */ PyObject *co_freevars; /* tuple of strings (free variable names) */ PyObject *co_cellvars; /* tuple of strings (cell variable names) */ /* The rest aren't used in either hash or comparisons, except for co_name (used in both) and co_firstlineno (used only in comparisons). This is done to preserve the name and line number for tracebacks and debuggers; otherwise, constant de-duplication would collapse identical functions/lambdas defined on different lines. */ unsigned char *co_cell2arg; /* Maps cell vars which are arguments. */ PyObject *co_filename; /* unicode (where it was loaded from) */ PyObject *co_name; /* unicode (name, for reference) */ int co_firstlineno; /* first source line number */ PyObject *co_lnotab; /* string (encoding addr<->lineno mapping) See Objects/lnotab_notes.txt for details. */ void *co_zombieframe; /* for optimization only (see frameobject.c) */ PyObject *co_weakreflist; /* to support weakrefs to code objects */ } PyCodeObject;
Berikut ialah peranan setiap medan dalam objek kod:
Pertama sekali, anda perlu memahami konsep blok kod Apa yang dipanggil blok kod ialah kod Python Kecil dilaksanakan sebagai unit kecil. Blok kod biasa dalam Python termasuk: badan fungsi, definisi kelas dan modul.
argcount, ini mewakili bilangan parameter dalam blok kod Parameter ini hanya berguna untuk blok kod badan fungsi, kerana fungsi itu mungkin mempunyai parameter, seperti pycdemo.py di atas. ialah modul Daripada fungsi, nilai yang sepadan bagi parameter ini ialah 0.
co_code, kandungan khusus objek ini ialah jujukan bait, yang menyimpan kod bait ular sawa sebenar Ia digunakan terutamanya untuk pelaksanaan mesin maya python dan tidak akan disertakan dalam artikel ini analisis terperinci.
co_consts, medan ini ialah medan jenis senarai, terutamanya mengandungi beberapa pemalar rentetan dan pemalar berangka, seperti "__main__" dan 100 di atas.
co_filename, maksud medan ini ialah nama fail bagi fail sumber yang sepadan.
co_firstlineno, maksud medan ini ialah bilangan baris dalam baris pertama kod dalam fail sumber python. Medan ini sangat penting semasa menyahpepijat.
co_flags, maksud utama medan ini adalah untuk mengenal pasti jenis objek kod ini. 0x0080 menunjukkan bahawa blok ini ialah coroutine, 0x0010 menunjukkan bahawa objek kod ini bersarang, dan seterusnya.
co_lnotab, maksud medan ini digunakan terutamanya untuk mengira bilangan baris kod sumber yang sepadan dengan setiap arahan bytecode.
co_varnames, maksud utama medan ini adalah untuk mewakili nama yang ditakrifkan secara setempat dalam objek kod.
co_names, bertentangan dengan co_varnames, mewakili nama yang tidak ditakrifkan secara setempat tetapi digunakan dalam objek kod.
co_nlocals, medan ini menunjukkan bilangan pembolehubah yang digunakan secara setempat dalam objek kod.
co_stackszie, kerana mesin maya python ialah komputer tindanan, nilai parameter ini menunjukkan nilai maksimum yang diperlukan untuk tindanan ini.
co_cellvars, co_freevars, kedua-dua medan ini terutamanya berkaitan dengan fungsi bersarang dan penutupan fungsi Kami akan menerangkan medan ini secara terperinci dalam artikel berikutnya.
Kini kami menggunakan beberapa contoh praktikal untuk menganalisis objek kod tertentu.
import dis import binascii import types d = 10 def test_co01(c): a = 1 b = 2 return a + b + c + d
Dalam artikel sebelumnya kami menyebut bahawa fungsi termasuk objek objek kod Hasil output objek objek kod test_co01 (lihat co01 untuk kod lengkap) adalah seperti berikut:
code argcount 1 nlocals 3 stacksize 2 flags 0043 0x43 code b'6401007d01006402007d02007c01007c0200177c0000177400001753' 9 0 LOAD_CONST 1 (1) 3 STORE_FAST 1 (a) 10 6 LOAD_CONST 2 (2) 9 STORE_FAST 2 (b) 11 12 LOAD_FAST 1 (a) 15 LOAD_FAST 2 (b) 18 BINARY_ADD 19 LOAD_FAST 0 (c) 22 BINARY_ADD 23 LOAD_GLOBAL 0 (d) 26 BINARY_ADD 27 RETURN_VALUE consts None 1 2 names ('d',) varnames ('c', 'a', 'b') freevars () cellvars () filename '/tmp/pycharm_project_396/co01.py' name 'test_co01' firstlineno 8 lnotab b'000106010601'
/* Masks for co_flags above */ #define CO_OPTIMIZED 0x0001 #define CO_NEWLOCALS 0x0002 #define CO_VARARGS 0x0004 #define CO_VARKEYWORDS 0x0008 #define CO_NESTED 0x0010 #define CO_GENERATOR 0x0020 /* The CO_NOFREE flag is set if there are no free or cell variables. This information is redundant, but it allows a single flag test to determine whether there is any extra work to be done when the call frame it setup. */ #define CO_NOFREE 0x0040 /* The CO_COROUTINE flag is set for coroutine functions (defined with ``async def`` keywords) */ #define CO_COROUTINE 0x0080 #define CO_ITERABLE_COROUTINE 0x0100
CO_OPTIMIZED, medan ini menunjukkan bahawa objek kod dioptimumkan, menggunakan fungsi setempat pembolehubah yang ditentukan.
CO_NEWLOCALS, maksud medan ini ialah apabila kod objek kod ini dilaksanakan, objek dict akan dibuat untuk objek f_locals dalam tindanan bingkai.
CO_VARARGS, menunjukkan sama ada objek kod ini mengandungi parameter kedudukan.
CO_VARKEYWORDS, menunjukkan sama ada objek kod ini mengandungi parameter kata kunci.
CO_NESTED, menunjukkan bahawa objek kod ini ialah fungsi bersarang.
CO_GENERATOR, menunjukkan bahawa objek kod ini ialah penjana.
CO_COROUTINE, menunjukkan bahawa objek kod ini ialah fungsi coroutine.
CO_ITERABLE_COROUTINE, menunjukkan bahawa objek kod ialah fungsi coroutine boleh lelar.
CO_NOFREE, ini bermakna tiada freevar dan cellvar, iaitu tiada penutupan fungsi.
我们使用下面的函数来对这两个字段进行分析:
def test_co02(): a = 1 b = 2 def g(): return a + b return a + b + g()
上面的函数的信息如下所示(完整代码见co02):
code argcount 0 nlocals 1 stacksize 3 flags 0003 0x3 code b'640100890000640200890100870000870100660200640300640400860000' b'7d0000880000880100177c00008300001753' 15 0 LOAD_CONST 1 (1) 3 STORE_DEREF 0 (a) 16 6 LOAD_CONST 2 (2) 9 STORE_DEREF 1 (b) 18 12 LOAD_CLOSURE 0 (a) 15 LOAD_CLOSURE 1 (b) 18 BUILD_TUPLE 2 21 LOAD_CONST 3 (<code object g at 0x7f133ff496f0, file "/tmp/pycharm_project_396/co01.py", line 18>) 24 LOAD_CONST 4 ('test_co02.<locals>.g') 27 MAKE_CLOSURE 0 30 STORE_FAST 0 (g) 20 33 LOAD_DEREF 0 (a) 36 LOAD_DEREF 1 (b) 39 BINARY_ADD 40 LOAD_FAST 0 (g) 43 CALL_FUNCTION 0 (0 positional, 0 keyword pair) 46 BINARY_ADD 47 RETURN_VALUE consts None 1 2 code argcount 0 nlocals 0 stacksize 2 flags 0013 0x13 code b'8800008801001753' 19 0 LOAD_DEREF 0 (a) 3 LOAD_DEREF 1 (b) 6 BINARY_ADD 7 RETURN_VALUE consts None names () varnames () freevars ('a', 'b') cellvars () filename '/tmp/pycharm_project_396/co01.py' name 'g' firstlineno 18 lnotab b'0001' 'test_co02.<locals>.g' names () varnames ('g',) freevars () cellvars ('a', 'b') filename '/tmp/pycharm_project_396/co01.py' name 'test_co02' firstlineno 14 lnotab b'0001060106021502'
从上面的输出我们可以看到的是,函数 test_co02 的 cellvars 为 ('a', 'b'),函数 g 的 freevars 为 ('a', 'b'),cellvars 表示在其他函数当中会使用本地定义的变量,freevars 表示本地会使用其他函数定义的变量。
再来分析一下函数 test_co02 的 flags,他的 flags 等于 0x3 因为有闭包的存在因此 flags 不会存在 CO_NOFREE,也就是少了值 0x0040 。
这个字段存储的是在函数在被虚拟机执行的时候所需要的最大的栈空间的大小,这也是一种优化手段,因为在知道所需要的最大的栈空间,所以可以在函数执行的时候直接分配指定大小的空间不需要在函数执行的时候再去重新扩容。
def test_stack(): a = 1 b = 2 return a + b
上面的代码相关字节码等信息如下所示:
code argcount 0 nlocals 2 stacksize 2 flags 0043 0x43 code b'6401007d00006402007d01007c00007c01001753' # 字节码指令 # 字节码指令参数 # 参数对应的值 24 0 LOAD_CONST 1 (1) 3 STORE_FAST 0 (a) 25 6 LOAD_CONST 2 (2) 9 STORE_FAST 1 (b) 26 12 LOAD_FAST 0 (a) 15 LOAD_FAST 1 (b) 18 BINARY_ADD 19 RETURN_VALUE consts None # 下标等于 0 的常量 1 # 下标等于 1 的常量 2 # 下标等于 2 的常量 names () varnames ('a', 'b') freevars () cellvars ()
我们现在来模拟一下执行过程,在模拟之前我们首先来了解一下上面几条字节码的作用:
LOAD_CONST,将常量表当中的下标等于 i 个对象加载到栈当中,对应上面的代码 LOAD_CONST 的参数 i = 1。因此加载测常量等于 1 。因此现在栈空间如下所示:
STORE_FAST,将栈顶元素弹出并且保存到 co_varnames 对应的下标当中,根据上面的字节码参数等于 0 ,因此将 1 保存到 co_varnames[0] 对应的对象当中。
LOAD_CONST,将下标等于 2 的常量加载进入栈中。
STORE_FAST,将栈顶元素弹出,并且保存到 varnames 下标为 1 的对象。
LOAD_FAST,是取出 co_varnames 对应下标的数据,并且将其压入栈中。我们直接连续执行两个 LOAD_FAST 之后栈空间的布局如下:
BINARY_ADD,这个字节码指令是将栈空间的两个栈顶元素弹出,然后将两个数据进行相加操作,然后将相加得到的结果重新压入栈中。
RETURN_VALUE,将栈顶元素弹出并且作为返回值返回。
从上面的整个执行过程来看整个栈空间使用的最大的空间长度为 2 ,因此 stacksize = 2 。
Atas ialah kandungan terperinci Apakah peranan Code obejct dalam mesin maya Python?. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!