MyCode= CodeType(
0,
0,
0,
3,
64,
bytes([101, 0, 0, #Load print function
101, 1, 0, #Load name 'a'
101, 2, 0, #Load name 'b'
23, #Take first two stack elements and store their sum
131, 1, 0, #Call first element in the stack with one positional argument
1, #Pop top of stack
101, 0, 0, #Load print function
101, 1, 0, #Load name 'a'
101, 2, 0, #Load name 'b'
20, #Take first two stack elements and store their product
131, 1, 0, #Call first element in the stack with one positional argument
1, #Pop top of stack
100, 0, 0, #Load constant None
83]), #Return top of stack
(None,),
('print', 'a', 'b'),
(),
'PersonalCodeObject',
'MyCode',
1,
bytes([14,1]),
(),
() )
a=2
b=3
exec(MyCode) # code prints the sum and the product of "a" and "b"
–––––––––––
免责声明 此答案中的文档不是官方的,可能不正确。
此答案仅对Python3.x版有效
———————————————————
要创建代码对象,必须将以下参数传递给函数CodeType():
现在我将试着解释每一个论点的含义。
参数计数
要传递给函数的参数数(*不包括args和**kwargs)。
kwonlyargcount
keyword-only arguments的数目。
非本地
局部变量的数量,
即除全局名称外的所有变量和参数(包括参数和**kwargs)。
堆叠大小 代码所需的堆栈(虚拟机堆栈)数量,
如果您想了解它是如何工作的,请参见官方的Documentation。
标志
表示代码对象的位图:
1–>;代码已优化
2–>;newlocals:有一个新的本地命名空间(例如一个函数)
4–>;代码接受任意数量的位置参数(*使用args)
8–>;代码接受任意数量的关键字参数(使用kwargs)
32–>;代码是生成器
othes标志在较旧的python版本中使用,或者被激活以说明从未来导入的内容
代码字符串
表示字节码指令的字节序列 如果您想要更好的理解,请参见Documentation(同上)
常量
包含字节码使用的文本的元组(例如,预先计算的数字、元组和字符串)
姓名
包含字节码使用的名称的元组
这些名称是全局变量、函数和类,也可以是从对象加载的属性
变量名
包含字节码使用的本地名称的元组(首先是参数,然后是本地变量)
文件名
它是编译代码的文件名。
它可以是你想要的任何东西,你可以在这件事上撒谎。;)
姓名
它给出了函数的名称。 这也可以是你想要的任何东西,但是要小心:
这是回溯中显示的名称,如果名称不清楚,则回溯可能不清楚,
想想lambdas有多烦人。
第一行编号 函数的第一行(如果编译了源代码,则用于调试)
总数
将字节码偏移量与行号相关联的字节映射。
(我认为这也是为了调试的目的,关于这方面的文档很少)
自由变量
包含自由变量名称的元组。
自由变量是在定义代码对象的命名空间中声明的变量, 它们在声明嵌套函数时使用;
这不会在模块级发生,因为在这种情况下,自由变量也是全局变量。
单元变量
包含嵌套函数引用的局部变量名的元组。
–––––––––––
示例:
下面的例子应该澄清上面所说的意思。
注意:在上面提到的finished code objects属性的前缀是
函数的可执行体存储在
–––––––––––
第一个示例
输出:
传递给此函数的参数有两个(“a”、“b”)
此函数有两个参数(“a”、“b”)和三个局部变量(“k”、“w”、“p”)
通过t分解函数ecode我们得到:
正如您可以注意到chile正在执行该函数一样,堆栈中的元素永远不会超过三个(在本例中,元组计算为其长度)
flag的值是dec67=bin10000011=bin1000000+10+1=dec64+2+1,因此我们知道
函数中使用的唯一全局名称是“c”,它存储在co_names中
我们使用的每一个显式文字都存储在co consts中:
–––––––––––
第二个例子
输出:
输出的含义如下:
第一行和第二行是在执行F时打印的,因此它们显示G代码的co-freevars和co-u名称:
“FunctionVar”位于F function的命名空间中,其中G是创建的,
“ModuleVar”是一个模块变量,因此它被视为全局变量。
下面三行是关于F代码的co廑cellvars、co廑freevars和co廑names属性:
“FunctionVar”在G嵌套函数中被引用,因此它被标记为cellvar,
“ModuleVar”在创建F的命名空间中,但它是一个模块变量,
因此它没有标记为freevar,但在全局名称中找到。
此外,内置函数print在names和F中使用的所有属性名中都有标记
–––––––––––
第三个例子
这是一个工作代码对象初始化,
这是不实用的,但是你可以用这个函数做任何你想做的事情。
输出:
代码类型构造函数的示例用法可以在标准库中找到,特别是Lib/modulefinder.py。如果你看那里,你会看到它被用来重新定义文件中所有代码对象的只读
co_filename
属性。我最近遇到了一个类似的用例,在那里我有一个函数工厂,但是生成的函数在回溯中总是有一个“通用”名称,所以我必须重新生成代码对象以包含所需的名称。
但是,等等,函数的
__code__
成员不是只读的,因此我们可以执行modulefinder所做的操作:在这个例子中要注意的是,在堆栈跟踪中生成值时,回溯使用
co_name
属性,而不是func.__name__
属性。还有一点要注意:上面是Python 3,为了使它与Python 2兼容,只需省略构造函数的第二个参数(
co_kwonlyargcount
)。更新:VictorStinner在Python3.8的CodeType类中添加了一个新方法“replace”,这大大简化了这种情况。这样做是为了消除将来的兼容性问题,因为3.8还在“co_argcount”之后的调用列表中添加了一个新的“co_posonlyargcount”参数,因此,如果参数列表再次更改,至少3.8和更高版本的代码将在将来得到一定程度的验证。
相关问题 更多 >
编程相关推荐