我想创建一个新的代码对象与功能types.CodeType()。
有关于这几乎没有任何文档和现有的人说“不适合心脏微弱”
告诉我我需要什么,给我约传递给types.CodeType每个参数的一些信息,
可能张贴的例子。
注意 :
在正常使用情况下,你只需要内置函数编译()
您应该使用types.CodeType()只如果你想创建一个不能获得正常书写源代码的新的指令和要求,以字节码的直接访问。
我想创建一个新的代码对象与功能types.CodeType()。
有关于这几乎没有任何文档和现有的人说“不适合心脏微弱”
告诉我我需要什么,给我约传递给types.CodeType每个参数的一些信息,
可能张贴的例子。
注意 :
在正常使用情况下,你只需要内置函数编译()
您应该使用types.CodeType()只如果你想创建一个不能获得正常书写源代码的新的指令和要求,以字节码的直接访问。
-----------
免责声明 :
在这个答案的文档是不是官方的,可能是不正确的。
这个答案只适用于蟒3.x版
-----------
为了创建你要传递给函数CODETYPE()以下参数代码对象:
CodeType(
argcount, # integer
kwonlyargcount, # integer
nlocals, # integer
stacksize, # integer
flags, # integer
codestring, # bytes
consts, # tuple
names, # tuple
varnames, # tuple
filename, # string
name, # string
firstlineno, # integer
lnotab, # bytes
freevars, # tuple
cellvars # tuple
)
现在,我会尽量解释什么是每个参数的意义。
argcount
要传递给函数的自变量数(*指定参数和** kwargs不包括在内)。
kwonlyargcount
数只有关键字的参数 。
nlocals
局部变量的数目,
即所有变量和参数(*指定参数和** kwargs包括在内),除了全局名称。
STACKSIZE堆的由代码所需要的量(虚拟机堆),
如果你想了解它是如何工作的,请参阅官方文档 。
旗
位图,说一些有关的代码对象:
1 - >代码进行了优化
2 - > newlocals:有一个新的本地名称空间中(例如,函数)
4 - >的代码接受的位置参数的任意数量(* ARGS使用)
8 - >的代码接受的keyworded参数的任意数量(* kwargs使用)
32 - >的代码是发电机
othes标志在老的Python版本中使用或激活该说些什么,从未来 __ __进口
码流
表示字节码指令的字节序列
如果你想有一个更好的了解,请参阅文档 (同上)
consts
一种包含由字节码中使用文字元组(例如预先计算的数字,元组和字符串)
名
使用字节码含有名称元组
这个名字是全局变量,函数和类或者也可在对象属性中加载
varnames
一种包含由字节码中使用本地名称元组(第一参数,然后局部变量)
文件名
它是从哪个编译代码的文件名。
它可以是任何你想要的,你可以自由地撒谎这一点。 ;)
名称
它给出了函数的名称。 这也可能是你想要的,但要注意:
这是在回溯中显示的名称,如果名称不明确的,回溯可能是不清楚,
只是想想如何lambda表达式可以是恼人。
firstlineno
该函数的第一行(用于调试的目的,如果你编译源代码)
lnotab
字节的映射该相关的字节码偏移量行号。
(我想这也就是为调试目的,有几个文档关于本)
freevars
含自由变量的名称元组。
自由变量是在命名空间声明的变量,其中被定义的代码对象,当嵌套函数被声明它们被使用;
这并不在模块级发生的,因为在这种情况下自由变量也是全局变量。
cellvars
一个包含嵌套函数引用的局部变量的名称元组。
------------
例子 :
下面的例子应该澄清上面已经说的意思。
注 :在完成代码对象上面提到的有CO_前缀属性,
和存储功能的可执行体在__code__属性
------------
第1例
def F(a,b):
global c
k=a*c
w=10
p=(1,"two",3)
print(F.__code__.co_argcount)
print(F.__code__.co_nlocals , F.__code__.co_varnames)
print(F.__code__.co_stacksize)
print(F.__code__.co_flags)
print(F.__code__.co_names)
print(F.__code__.co_consts)
输出:
2
5 ('a', 'b', 'k', 'w', 'p')
3
67
('c' ,)
(None, 10, 1, 'two'. 3, (1, 'two', 3))
有传递给此函数(“A”,“B”)的两个参数
这个函数有两个参数( “A”, “B”)和三个局部变量( “K”, “W”, “P”)
拆卸功能字节码,我们得到这样的:
3 0 LOAD_FAST 0 (a) #stack: ["a"] 3 LOAD_GLOBAL 0 (c) #stack: ["a","c"] 6 BINARY_MULTIPLY #stack: [result of a*c] 7 STORE_FAST 2 (k) #stack: [] 4 10 LOAD_CONST 1 (10) #stack: [10] 13 STORE_FAST 3 (w) #stack: [] 5 16 LOAD_CONST 5 ((1, 'two', 3)) #stack: [(1,"two",3)] 19 STORE_FAST 4 (p) #stack: [] 22 LOAD_CONST 0 (None) #stack: [None] 25 RETURN_VALUE #stack: []
你可以注意到智利执行功能,我们从来没有在堆栈以上三个元素(数组数为lenght在这种情况下)
标志的值是十进制 67 = 斌 1000011 = 斌百万+10 + 1 = 64 月 +2 +1,所以我们明白
这是在函数中使用的全球唯一的名称是“C”,它存储在co_names
我们利用每一个明确的文字保存在co_consts:
------------
第二个例子
ModuleVar="hi"
def F():
FunctionVar=106
UnusedVar=ModuleVar
def G():
return (FunctionVar,ModuleVar)
print(G.__code__.co_freevars)
print(G.__code__.co_names)
F()
print(F.__code__.co_cellvars)
print(F.__code__.co_freevars)
print(F.__code__.co_names)
输出:
('FunctionVar',)
('ModuleVar',)
('FunctionVar',)
()
('print', '__code__', 'co_freevars', 'co_names', 'ModuleVar')
输出的意思是这样的:
执行F如果第一和第二线被印刷,因此它们显示出co_freevars和的G代码co_names:
“FunctionVar”是在F函数的名称空间,其中G被创建,
“ModuleVar”,而不是一个模块变量,因此它被认为是全球性的。
以下三条线约co_cellvars,co_freevars和F的代码co_names属性:
“FunctionVar”是在G嵌套函数引用的,所以它被标记为一个cellvar,
“ModuleVar”是其中F被创建的命名空间,但它是一个模块变量,
所以它没有标记为freevar,但它在全球的名字找到。
还内建函数打印标记的名称,并在使用F.属性的所有名称
------------
第三个例子
这是一个工作代码对象初始化,
这是无用的,但你可以做你想要使用此功能应有尽有。
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"
输出:
5
6
所述CODETYPE构造的实施例的使用可以在标准库中找到,特别是LIB / modulefinder.py。 如果你看那里,你会看到它被用来重新定义只读co_filename
在一个文件中的所有代码对象的属性。
我最近遇到了一个类似用途的情况下我有一个函数工厂,但生成的函数总是在回溯了“通用”的名字,让我不得不重新生成代码的对象包含所需的名称。
>>> def x(): raise NotImplementedError
...
>>> x.__name__
'x'
>>> x.__name__ = 'y'
>>> x.__name__
'y'
>>> x()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 1, in x
NotImplementedError
>>> x.__code__.co_name
'x'
>>> x.__code__.__name__ = 'y'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: readonly attribute
>>> 'Gah!'
'Gah!'
但是,等待,函数的__code__
成员不是只读的,所以我们可以做modulefinder做什么:
>>> from types import CodeType
>>> co = x.__code__
>>> x.__code__ = CodeType(co.co_argcount, co.co_kwonlyargcount,
co.co_nlocals, co.co_stacksize, co.co_flags,
co.co_code, co.co_consts, co.co_names,
co.co_varnames, co.co_filename,
'MyNewCodeName',
co.co_firstlineno, co.co_lnotab, co.co_freevars,
co.co_cellvars)
>>> x.__code__.co_name
'MyNewCodeName'
>>> x()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 1, in MyNewCodeName
NotImplementedError
在这个例子中要注意的一点是,回溯使用co_name
属性,而不是func.__name__
在堆栈跟踪生产值时,属性。
还要说明一点:以上是Python 3中,以使Python 2兼容,只是离开了第二个参数的构造函数( co_kwonlyargcount
)。