您现在的位置是:主页 > news > 北京网站托管公司/游戏推广员每天做什么

北京网站托管公司/游戏推广员每天做什么

admin2025/5/9 8:32:09news

简介北京网站托管公司,游戏推广员每天做什么,网站建设招聘,吉安做网站优化pPython是一门解释型语言,边解释边执行(效率比C低,暴力脚本经常炸),通常不会进行整体地编译和链接,使用专门的解释器逐行编译解释成特定字节码,其工作流程如下: 1. 将源代码编译转换为字节码2. 解释器执行字…

北京网站托管公司,游戏推广员每天做什么,网站建设招聘,吉安做网站优化pPython是一门解释型语言,边解释边执行(效率比C低,暴力脚本经常炸),通常不会进行整体地编译和链接,使用专门的解释器逐行编译解释成特定字节码,其工作流程如下: 1. 将源代码编译转换为字节码2. 解释器执行字…

     pPython是一门解释型语言,边解释边执行(效率比C低,暴力脚本经常炸),通常不会进行整体地编译和链接,使用专门的解释器逐行编译解释成特定字节码,其工作流程如下: 

    1. 将源代码编译转换为字节码

    2. 解释器执行字节码(是不是像虚拟机?)

01pyc文件的生成

    pyc 文件是 py 文件编译后生成的字节码文件,在 __pycache__ 目录中。

    其目的是提高加载速度:运行时会检查字节码文件修改时间是否与源代码一致,一致则编译步骤将会被跳过,解释器直接加载 pyc 文件;否则编译保存新生成的字节码。 

    一般以 module 形式加载时,会生成 pyc 文件。

    pyc 文件生成方式有很多,如下列举了几种:

1命令
python -m test
2代码

1  生成单个 pyc 文件

    py_compile 编译

import py_compile py_compile.compile(r'path/test.py')

     load_module 间接加载

import impdef generate_pyc(name):    fp, pathname, description = imp.find_module(name)             try:        imp.load_module(name, fp, pathname, description)    finally:        if fp:            fp.close()if __name__ == '__main__':    generate_pyc(input())

2  批量生成 pyc 文件

import compileall compileall.compile_dir(r'path')
02pyc文件格式解析

pyc文件一般由三个部分组成:

  • 最开始 4 个字节是一个 Maigc int,标识此 pyc 的版本信息,不同的版本的 Magic 都在 python/import.c 内定义 

  • 接下来 4 个字节还是个 int,是 pyc 产生的时间(TIMESTAMP, 1970.01.01 到产生 pyc 时候的秒数)

  • 接下来是个序列化了的 PyCodeObject,此结构在 Include/code.h 内定义,序列化方法在 python/marshal.c 内定义 

    康一个实例(Python2.7,010editor template 用官方 PYC.bt)

print(2333)

6a04c8744f23348b9490e4ae98cdd23c.png

struct Magic magic       0A0DF303h char mtime[4]            5E6E3AB6h TYPE_CODE (63h)    int co_argcount         0h     int co_nlocals          0h     int co_stacksize        1h     int co_flags            40h     struct PyObject code         enum ObjType type                  TYPE_STRING (73h)         int n                              9h         64 00 00 47 48 64 01 00               struct Instruction inst[0]     LOAD_CONST 0         opcode 64h oparg 0h               struct Instruction inst[1]     PRINT_ITEM           opcode 47h                       struct Instruction inst[2]     PRINT_NEWLINE        opcode 48h                       struct Instruction inst[3]     LOAD_CONST 1         opcode 64h oparg 1h               struct Instruction inst[4]     RETURN_VALUE         opcode 53h         struct PyObject co_consts             enum ObjType type                     TYPE_TUPLE (28h)             int n                                 2h                 TYPE_INT (69h)                    91Dh(2333)                 TYPE_NONE (4Eh)     struct PyObject co_names     struct PyObject co_varnames     struct PyObject co_freevars     struct PyObject co_cellvars     struct PyObject co_filename         enum ObjType type                           TYPE_STRING (73h)         int n                                       9h         ./test.py     struct PyObject co_name         enum ObjType type                           TYPE_INTERNED (74h)         int n                                       8h              int co_firstlineno         1h     struct PyObject co_lnotab

    每个作用域(block)对应一个 PyCodeObject 对象,在 Python 源码目录下 Include/code.h 文件 中,可以看到 PyCodeObject 的定义如下:

/* Bytecode object */ typedef struct {     PyObject_HEAD     int co_argcount; /* #arguments, except *args */     int co_nlocals; /* #local variables */     int co_stacksize; /* #entries needed for evaluation stack */     int co_flags; /* CO_..., see below */     PyObject *co_code; /* instruction opcodes | code对应的字节码 */     PyObject *co_consts; /* list (constants used) | 所有常量组成的tuple */     PyObject *co_names; /* list of strings (names used) | code所用的到符 号表,tuple类型,元素是字符串 */     PyObject *co_varnames; /* tuple of strings (local variable names) | code所用到的局部变量名,tuple类型,元素是PyStringObject('s/t/R') */     PyObject *co_freevars; /* tuple of strings (free variable names) */     PyObject *co_cellvars; /* tuple of strings (cell variable names) */     PyObject *co_filename; /* unicode (where it was loaded from) */     PyObject *co_name; /* unicode (name, for reference) */    PyObject *co_lnotab; /* string (encoding addrlineno mapping) See Objects/lnotab_notes.txt for details. */ } PyCodeObject;
03Python字节码“反汇编”分析

    Python 提供 dis 模块,为 Python 字节码提供 “反汇编”,通过 dis.dis() 或 dis.disassemble() 可获得字节码的可阅读理解版本,可以看作虚拟机 opcode。 

    通过使用 dis.dis() 可以对代码实现进行比较,像是“为什么 {} 比 dict() 更快”的问题,能够更加 直接得到解答。

    来看一个简单的例子:(我后悔了,我为什么要写这么长的例子。

import dis def test():     a = 'hello'     b = 2     c = 3782     d = a + str(b + c)     print(d) if __name__ == '__main__':     test()     dis.dis(test)

     通过 dis 得到能分析的 opcode,第一列是源代码行数,第二列是字节偏移,第三列是命令,第四列是命令参数。

>Python3 test.py hello3784 5         0 LOAD_CONST          1 ('hello')          # 将co_consts[1] 即'hello'字符串压栈          2 STORE_FAST          0 (a)                # 将栈顶TOS存放到 co_varnames[0]即变量a 6         4 LOAD_CONST          2 (2)                # 将co_consts[2]即数 值2压栈           6 STORE_FAST          1 (b)                # 将TOS存放到 co_varnames[1]即变量b 7         8 LOAD_CONST          3 (3782)             # 将co_consts[3]即数 值3782压栈                   10 STORE_FAST         2 (c)                # 将TOS存放到 co_varnames[2]即变量c 8         12 LOAD_FAST          0 (a)                # 将co_varnames[0]即 变量a压栈           14 LOAD_GLOBAL        0 (str)              # 将co_names[0]即str 压栈          16 LOAD_FAST          1 (b)                # 将co_varnames[1]即 变量b压栈           18 LOAD_FAST          2 (c)                # 将co_varnames[2]即 变量c压栈           20 BINARY_ADD                              # 将栈顶的变量c和变量b 弹出,并做相加运算,将结果压栈           22 CALL_FUNCTION      1                    # 调用参数数量为1个的函 数,即str(b+c)           24 BINARY_ADD                              # 弹出栈顶的字符串a和 temp=str(b+c),连接,将结果压栈           26 STORE_FAST         3 (d)                # 将TOS存放到 co_varnames[3]即变量d 9         28 LOAD_GLOBAL        1 (print)            # 将co_names[1]即 print压栈                   30 LOAD_FAST          3 (d)                # 将co_varnames[3]即 变量d压栈           32 CALL_FUNCTION      1           34 POP_TOP                                 # 弹栈顶           36 LOAD_CONST         0 (None)             # 将co_consts[0]即空 对象None压栈           38 RETURN_VALUE                            # 返回TOS到调用者,返回 空

    Python 有着基于栈的运行机制。

    CPython 使用三种类型的栈: 

    1. 调用栈(call stack),为每个当前活动的函数调用使用了帧(frame)。栈底是程序的入口点,每个函 数调用会推送一个新的帧到调用栈,函数调用返回后帧被销毁。 

    2. 在每个函数/帧中,对应有一个 计算栈(evaluation stack) (也称为 据栈(data stack)),大多 数指令操作在计算栈中进行,如例子。 

    3. 在每个函数/帧中,对应有一个 块栈(block stack),被用于跟踪某些类型的控制结构:循环、 try / except 块、以及 with 块,进入这些控制结构时会被推入 Block 到块栈中。有助于了解 任意给定时刻的活动块,After all,一个 continue 或者 break 语句可能影响正确的块。

 部分指令操作

1 一般指令 

    POP_TOP :删除堆栈顶部(TOS)项。 

    ROT_TWO :交换两个最顶层的堆栈项。 

    DUP_TOP :复制堆栈顶部的引用。

2 Unary 一元操作

弹栈运算后压栈, UNARY_NEGATIVE 、 UNARY_NOT 、 UNARY_INVERT 、 GET_ITER(实现 TOS = iter(TOS) ) 

3 Binary 二元操作

弹出栈顶两个值运算后压栈, BINARY_POWER 、 BINARY_MULTIPLY 、 BINARY_MATRIX_MULTIPLY 、 BINARY_FLOOR_DIVIDE 、 BINARY_TRUE_DIVIDE 、 BINARY_MODULO 、 BINARY_ADD 、 BINARY_SUBTRACT 、 BINARY_SUBSCR (实现 TOS=TOS1[TOS] ,TOP1 为栈中第二 顶)、 BINARY_LSHIFT 、 BINARY_RSHIFT 、 BINARY_AND 、 BINARY_XOR 、 BINARY_OR 

4 Inplace 就地二元操作 

5 Load 压栈操作(相当于 push) 

    LOAD_CONST (consti):将 co_consts[consti] 的常量推入栈顶。 

    LOAD_GLOBAL (namei):加载名称为 co_names[namei] 的全局对象推入栈顶。 

    LOAD_FAST (var_num):将指向局部对象co_varnames[var_num] 的引用推入栈顶。

6 Store 弹栈赋值操作(相当于 top+pop)(对应 Load 种类) 

    STORE_FAST (var_num):将 TOS 存放到局部变量 co_varnames[var_num] 。

7 判断跳转循环 

    COMPARE_OP (opname):执行布尔运算操作。操作名称可在 cmp_op[opname] 中找到。相当于汇 编中的比较指令。

    POP_JUMP_IF_TRUE(FALSE) (target):如果 TOS 为真/假值,则将字节码计数器的值设为 target。TOS 会被弹出。        JUMP_IF_TRUE(FALSE)_OR_POP (target):如果 TOS 为真/假值,则将字节码计数器的值设为 target 并将 TOS 留在栈顶。否则(如 TOS 为假/真值),TOS 会被弹出。 

    JUMP_ABSOLUTE (target):将字节码计数器的值设为 target。    JUMP_FORWARD (delta):将字节码计数器的值增加 delta。        FOR_ITER (delta):TOS 是一个 iterator。可调用它的 __next__() 方法。如果产生了一个新值, 则将其推入栈顶(将迭代器留在其下方)。如果迭代器提示已耗尽则 TOS 会被弹出,并将字节码 计数器的值增加 delta。 

    SETUP_LOOP (delta):将要循环的代码块压入堆栈。该代码块从当前指令开始扩展,大小为 delta 字节。 

    BREAK_LOOP 

    CONTINUE_LOOP (target) 

8 函数调用

    CALL_FUNCTION (argc):调用一个可调用对象并传入位置参数。argc 指明位置参数的数量。栈顶 包含位置参数,其中最右边的参数在最顶端。在参数之下是一个待调用的可调用对象。        

    CALL_FUNCTION 会从栈中弹出所有参数以及可调用对象,附带这些参数调用该可调用对象,并将 可调用对象所返回的返回值推入栈顶。在 3.6 版更改: 此操作码仅用于附带位置参数的调用。        

    RETURN_VALUE :返回 TOS 到函数的调用者。

列出来不够直观,再康几个例子。

1循环 

1.for 循环

def test():     for i in range(0x10):         pass
5         0 SETUP_LOOP          16 (to 18)              # 循环开始           2 LOAD_GLOBAL         0 (range)           4 LOAD_CONST          1 (16)           6 CALL_FUNCTION       1                       # 函数调用,range(16)           8 GET_ITER                                    # TOS=iter(TOS),即将 指向栈顶的指针压栈 >>           10 FOR_ITER           4 (to 16)               # 不断调用即可遍历 iterator(range(16)),将每次产生的新值放于栈顶,迭代器上方,迭代器耗尽时弹出并修改字节码计 数器增加4,即跳到12(字节码计数器当前值)+4=16POP_BLOCK           12 STORE_FAST         0 (i) 6         14 JUMP_ABSOLUTE      10                      # 简言之,蹦到10     >>    16 POP_BLOCK                                  # 弹出循环Block     >>    18 LOAD_CONST         0 (None)                # 函数结束部分           20 RETURN_VALUE

2.while 循环

def test():     i = 0 while i < 0x16:         i += 1
5          0 LOAD_CONST                      1 (0)            2 STORE_FAST                      0 (i) 6          4 SETUP_LOOP                      20 (to 26)         # 循环开始,循环Block压 栈,大小为20    >>     6 LOAD_FAST                       0 (i)            8 LOAD_CONST                      2 (22)            10 COMPARE_OP                     0 (           12 POP_JUMP_IF_FALSE              24                 # 弹出TOS,如果为假值, 则将字节码计数器的值设为24,即跳到24POP_BLOCK 7          14 LOAD_FAST                      0 (i)            16 LOAD_CONST                     3 (1)            18 INPLACE_ADD            20 STORE_FAST                     0 (i)            22 JUMP_ABSOLUTE                  6                   # 跳到6      >>    24 POP_BLOCK      >>    26 LOAD_CONST                     0 (None)           28 RETURN_VALUE
2函数调用
def test():     return testt(2, 3, 5) def testt(a, b, c):     return a + b - c
5       0 LOAD_GLOBAL            0 (testt)         2 LOAD_CONST             1 (2)         4 LOAD_CONST             2 (3)         6 LOAD_CONST             3 (5)         8 CALL_FUNCTION          3             # 函数调 用,testt(2,3,5),返回值压栈         10 RETURN_VALUE                        # 返回TOS到函数的调用者
04参考

dis — Python 字节码反汇编器 

https://docs.Python.org/zh-cn/3.6/library/dis.html

浮生半日:探究Python字节码

https://www.cnblogs.com/0xJDchen/p/6995204.html

PYC文件格式分析

https://kdr2.com/tech/Python/pyc-format.html