python - 如何在python中创建代码对象?

标签 python python-3.x bytecode

我想用函数类型.codeType()创建一个新的代码对象。
关于这一点,几乎没有文献记载,现有的文献说“心脏不虚弱”。
告诉我需要什么,并给我一些关于传递给types.codetype的每个参数的信息,
可能发布一个示例。
注:
在正常的用例中,您只需要内置函数compile()。
只有当您想创建新的指令,而这些指令在编写普通的源代码时无法获得,并且需要直接访问字节码时,才应该使用types.codetype()。

最佳答案

–––––––––-
免责声明:
此答案中的文档不是官方文档,可能不正确。
此答案仅对python 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数
要传递给函数的参数数(*args和**kwargs不包括在内)。
KwOnlyargCount(KwOnlyargCount)
keyword-only arguments的数目。
非本地语言
局部变量数量,
即除全局名称外的所有变量和参数(*args和**kwargs)。
堆栈大小
代码所需的堆栈(虚拟机堆栈)量,
如果您想了解它的工作原理,请参阅officialDocumentation
旗帜
表示代码对象的位图:
1–>代码已优化
2–>newlocals:有一个新的本地命名空间(例如函数)
4–>代码接受任意数量的位置参数(*args被使用)
8–>代码接受任意数量的关键字参数(*kwargs被使用)
32–>代码是一个生成器
其他标志在旧的python版本中使用,或者被激活来表示从未来导入的内容。__
代码字符串
表示字节码指令的字节序列。
如果您想要更好的理解,请参阅(与上面相同)
阵营
包含字节码使用的文本的元组(例如预计算的数字、元组和字符串)
姓名
包含字节码使用的名称的元组。
这些名称是全局变量、函数和类,或者也是从对象加载的属性。
变量名
包含字节码使用的本地名称的元组(先是参数,然后是局部变量)
文件名
它是编译代码的文件名。
它可以是你想要的任何东西,你可以就此说谎。;)
名称
它给出了函数的名称。
这也可以是你想要的,但是要小心:
这是回溯中显示的名称,如果名称不清楚,回溯可能不清楚,
想想羔羊有多烦人。
第一行编号
函数的第一行(如果编译了源代码,则用于调试)
勒诺布
将字节码偏移量与行号关联起来的字节映射。
(我认为这也是为了调试目的,关于这方面的文档很少)
自由变量
包含自由变量名称的元组。
自由变量是在定义代码对象的命名空间中声明的变量,
它们在声明嵌套函数时使用;
这不会在模块级别发生,因为在这种情况下,自由变量也是全局变量。
细胞变
包含嵌套函数引用的局部变量名的元组。
––––––––––-
示例:
下面的例子应该澄清上述内容的含义。
注意:在完成的代码对象中,上面提到的属性具有co_u前缀,
函数将其可执行体存储在uu code_uuu属性中
––––––––––-
第一个示例
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:  []

正如您可以注意到的,Chile执行函数时,堆栈中的元素永远不会超过三个(在本例中,tuple算作其长度)。
标志的值是dec 67=bin 1000011=bin 1000000+10+1=dec 64+2+1,所以我们理解
代码被优化(因为大多数自动生成的代码是这样的)
在执行函数字节码本地命名空间更改时
64?实际上我不知道它的意思是什么
函数中使用的唯一全局名称是“c”,它以co-u名称存储。
我们使用的每个显式文本都存储在co-consts中:
none是函数的返回值
我们明确地把数字10赋给w
我们明确地将(1,'2',3)分配给P
如果元组是常量,则该元组的每个元素都是常量,因此1,“2”,3是常量
––––––––––-
第二个示例
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时打印,因此它们显示g代码的co-freevars和co-u名称:
“functionvar”位于f函数的命名空间中,其中创建了g,
“modulevar”是一个模块变量,因此它被视为全局变量。
以下三行是关于f code的co-cellvars、co-freevars和co-names属性:
“functionvar”在g嵌套函数中被引用,因此它被标记为cellvar,
“modulevar”位于创建f的命名空间中,但它是一个模块变量,
因此,它没有标记为freevar,但可以在全局名称中找到。
此外,内置函数print以名称和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

关于python - 如何在python中创建代码对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16064409/

相关文章:

javascript - Django:无法从 Javascript 调用 python 函数

python:从给定列表中删除一组时出现KeyError

Python 3 从已排序的大文件中加入数据

java - 生成Jasmin j文件相对于Java源文件有什么优势?

python - 如何检查加载了什么网址?

python - Django:对象和模型集

python - 如何记住 python 3 中的 tkinter 窗口位置?

Python 3 "Lock"为 : threads and processes

java - 使用 Byte Buddy 拦截对 Java 8 lambda 表达式的调用

python - 有没有办法以编程方式生成 Python 字节码?