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;
다음은 코드 객체의 각 필드의 역할입니다.
우선 코드 블록이라는 개념을 이해해야 합니다. , 전체적으로 작은 단위로 실행됩니다. Python의 일반적인 코드 블록에는 함수 본문, 클래스 정의 및 모듈이 포함됩니다.
argcount는 코드 블록의 매개변수 수를 나타냅니다. 이 매개변수는 함수 본문 코드 블록에만 유용합니다. 예를 들어 위의 pycdemo.py는 함수가 아닌 모듈입니다. 이므로 이 매개변수의 해당 값은 0입니다.
co_code, 이 개체의 특정 콘텐츠는 실제 Python 바이트코드를 저장하는 바이트 시퀀스입니다. 이는 주로 Python 가상 머신 실행에 사용되며 이 기사에서는 자세히 분석하지 않습니다.
co_consts, 이 필드는 목록 유형 필드로, 주로 위의 "__main__" 및 100과 같은 일부 문자열 상수와 숫자 상수를 포함합니다.
co_filename, 이 필드의 의미는 해당 소스 파일의 파일 이름입니다.
co_firstlineno, 이 필드의 의미는 Python 소스 파일의 코드 첫 번째 줄에 나타나는 줄 수입니다. 이 필드는 디버깅할 때 매우 중요합니다.
co_flags, 이 필드의 주요 의미는 이 코드 개체의 유형을 식별하는 것입니다. 0x0080은 이 블록이 코루틴임을 나타내고, 0x0010은 이 코드 객체가 중첩되었음을 나타냅니다.
co_lnotab, 이 필드의 의미는 주로 각 바이트코드 명령어에 해당하는 소스 코드 줄 수를 계산하는 데 사용됩니다.
co_varnames, 이 필드의 주요 의미는 코드 개체에서 로컬로 정의된 이름을 나타내는 것입니다. co_varnames의 반대인
co_names는 로컬로 정의되지 않고 코드 개체에 사용되는 이름을 나타냅니다.
co_nlocals, 이 필드는 코드 객체에서 로컬로 사용되는 변수의 수를 나타냅니다.
co_stackszie, Python 가상 머신은 스택 컴퓨터이므로 이 매개변수의 값은 이 스택에 필요한 최대값을 나타냅니다.
co_cellvars, co_freevars, 이 두 필드는 주로 중첩 함수 및 함수 클로저와 관련이 있습니다. 이 필드에 대해서는 후속 기사에서 자세히 설명하겠습니다.
이제 몇 가지 실용적인 예를 사용하여 특정 코드 개체를 분석합니다.
import dis import binascii import types d = 10 def test_co01(c): a = 1 b = 2 return a + b + c + d
이전 기사에서 함수에 코드 개체 개체가 포함되어 있다고 언급했습니다. test_co01의 코드 개체 개체(전체 코드는 co01 참조)의 출력 결과는 다음과 같습니다.
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'
필드 값 argcount는 1과 같습니다. 이는 함수에 하나의 매개변수가 있고 이 함수 test_co01에는 서로 대응하는 매개변수 c가 있음을 나타냅니다.
nlocals 필드의 값은 3으로, 총 3개의 함수 로컬 변수 a, b, c가 test_co01 함수에 구현되어 있음을 나타냅니다.
필드 이름은 코드의 co_names에 해당합니다. 이전 정의에 따르면 전역 변수 d는 test_co01 함수에서 사용되지만 함수에서는 정의되지 않습니다.
Field varnames는 로컬 정의에 사용되는 변수를 나타냅니다. test_co01 함수에는 a, b, c 세 가지 주요 변수가 있습니다.
필드 파일 이름은 Python 파일의 주소입니다.
Field firstlineno는 함수의 첫 번째 줄이 해당 Python 코드의 8번째 줄에 나타남을 나타냅니다.
분석을 위해 특별히 python3.5의 소스 코드를 사용합니다. cpython 가상 머신의 구체적인 구현은 다음과 같습니다(Include/code.h):
/* 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
플래그 필드와 위의 각 매크로 정의는 & 연산을 수행하여 결과가 0보다 크면 해당 조건이 충족되었음을 의미합니다.
위 매크로 정의의 의미는 다음과 같습니다.
CO_OPTIMIZED 이 필드는 코드 개체가 최적화되었으며 함수에 의해 로컬로 정의된 변수를 사용함을 나타냅니다.
CO_NEWLOCALS, 이 필드의 의미는 이 코드 객체의 코드가 실행될 때 스택 프레임의 f_locals 객체에 대해 dict 객체가 생성된다는 것입니다.
CO_VARARGS - 이 코드 객체에 위치 매개변수가 포함되어 있는지 여부를 나타냅니다.
CO_VARKEYWORDS - 이 코드 객체에 키워드 매개변수가 포함되어 있는지 여부를 나타냅니다.
CO_NESTED, 이 코드 객체가 중첩 함수임을 나타냅니다.
CO_GENERATOR은 이 코드 객체가 생성기임을 나타냅니다.
CO_COROUTINE은 이 코드 객체가 코루틴 함수임을 나타냅니다.
CO_ITERABLE_COROUTINE은 코드 객체가 반복 가능한 코루틴 함수임을 나타냅니다.
CO_NOFREE 이는 freevar 및 cellvar가 없음, 즉 함수 폐쇄가 없음을 의미합니다.
이제 이전 함수 test_co01의 플래그를 분석해 보겠습니다. 해당 값은 0x43입니다. 이는 이 함수가 CO_NEWLOCALS, CO_OPTIMIZED 및 CO_NOFREE의 세 가지 특성을 충족한다는 의미입니다.
我们使用下面的函数来对这两个字段进行分析:
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 。
위 내용은 Python 가상 머신에서 Code 객체의 역할은 무엇입니까?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!