• python中的code object


    引入

    看一段python代码,打印一个函数的__code__,返回的是一个code object,code object是什么,有哪些属性呢?

    def f():
        pass
    f.__code__
    <code object f at 0x00000176FC4E8B30, file "", line 1>
    dir(f.__code__)
    ['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'co_argcount', 'co_cellvars', 'co_code', 'co_consts', 'co_filename', 'co_firstlineno', 'co_flags', 'co_freevars', 'co_kwonlyargcount', 'co_lnotab', 'co_name', 'co_names', 'co_nlocals', 'co_posonlyargcount', 'co_stacksize', 'co_varnames', 'replace']
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    code object的各个属性的含义可以参考官方文档code object属性含义

    co_argcountnumber of arguments (not including keyword only arguments, * or ** args)
    co_codestring of raw compiled bytecode
    co_cellvarstuple of names of cell variables (referenced by containing scopes)
    co_conststuple of constants used in the bytecode
    co_filenamename of file in which this code object was created
    co_firstlinenonumber of first line in Python source code
    co_flagsbitmap of CO_* flags, read more here
    co_lnotabencoded mapping of line numbers to bytecode indices
    co_freevarstuple of names of free variables (referenced via a function’s closure)
    co_posonlyargcountnumber of positional only arguments
    co_kwonlyargcountnumber of keyword only arguments (not including ** arg)
    co_namename with which this code object was defined
    co_qualnamefully qualified name with which this code object was defined
    co_namestuple of names other than arguments and function locals
    co_nlocalsnumber of local variables
    co_stacksizevirtual machine stack space required
    co_varnamestuple of names of arguments and local variables

    概念

    code object是一段可执行的python代码在CPython中的内部表示,包含一系列直接操作虚拟机内部状态的指令
    可执行的python代码包括函数,模块,,生成器表达式
    当运行一段代码时,程序被解析,编译成字节码,并被CPython虚拟机执行

    尝试

    容易理解的几个
    def f():
        pass
    
    
    code = f.__code__
    print(code.co_code)  # b'd\x00S\x00' 字节码
    print(code.co_name)  # f 函数名
    print(code.co_filename)  # D:\learn_py\code_object.py 文件名
    print(code.co_lnotab)  # b'\x00\x01' encoded mapping of line numbers to bytecode indices 行号与字节码的映射
    print(code.co_flags)  # 67 https://docs.python.org/3/library/inspect.html?highlight=__code__#inspect-module-co-flags
    print(code.co_stacksize)  # 1 virtual machine stack space required 虚拟机需要的栈空间
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    count

    co_argcount 表示除keyword only arguments, * or ** args外的参数个数
    co_posonlyargcount表示positional only arguments个数
    co_kwonlyargcount表示keyword only arguments (not including ** arg)

    def f(a, b=2, *args, **kwargs):
        pass
    
    
    code = f.__code__
    
    print(code.co_argcount)  # 2 number of arguments (not including keyword only arguments, * or ** args),不包括only keyword
    print(code.co_posonlyargcount)  # 0 number of positional only arguments
    print(code.co_kwonlyargcount)  # 0 number of keyword only arguments (not including ** arg)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    函数定义时可以用‘/’划分,将’/'前面的规定全为positional only arguments

    def f(a, b=2, /, *args, **kwargs):
        pass
    
    
    code = f.__code__
    
    print(code.co_argcount)  # 2 number of arguments (not including keyword only arguments, * or ** args),不包括only keyword
    print(code.co_posonlyargcount)  # 2 number of positional only arguments
    print(code.co_kwonlyargcount)  # 0 number of keyword only arguments (not including ** arg)
    f(1, 1)
    f(1)
    f(a=1)  # 报错TypeError: f() missing 1 required positional argument: 'a'
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    同时还可以用‘‘划分,’'后面的全部都是keyword only arguments

    def f(a, *, b=2, **kwargs):
        pass
    
    
    code = f.__code__
    
    print(code.co_argcount)  # 1 number of arguments (not including keyword only arguments, * or ** args),不包括only keyword
    print(code.co_posonlyargcount)  # 0 number of positional only arguments
    print(code.co_kwonlyargcount)  # 1 number of keyword only arguments (not including ** arg)
    
    f(a=1)
    f(1)
    f(1, 2)  # TypeError: f() takes 1 positional argument but 2 were given
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    names
    def f(a):
        import math as m
        b = a.attr
        c = 2
        e = 3
        f1 = "xxxx"
        d1 = c + b
        return b
    import dis
    dis.dis(f)
    
    code = f.__code__
    print(code.co_nlocals)  # 7 局部变量的数量,等于co_varnames的size
    print(code.co_varnames)  # ('a', 'm', 'b', 'c', 'e', 'f1', 'd1') local variables 的string
    print(code.co_names)  # ('math', 'attr') 除了co_varnames,co_cellvars, co_freevars之外的其他
    print(code.co_cellvars)
    print(code.co_freevars)
    print(code.co_consts)  # (None, 0, 2, 3, 'xxxx') 出现的常量如数字,字符串
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    co_cellvars和co_freevars常在闭包中成对出现,co_freevars表示用到了scope之外的变量,co_cellvars表示变量被其他scope使用

    def g():
        a = {}
    
        def f():
            pass
        return f
    
    
    code = g.__code__
    print(code.co_varnames)
    print(code.co_cellvars)
    print(code.co_freevars)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    def g():
        a = {}
    
        def f():
            a["name"] = "haha"
            pass
        return f
    
    
    code = g.__code__
    print(code.co_varnames)  # ('f',)
    print(code.co_cellvars)  # ('a',)
    print(code.co_freevars)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    def g():
        a = {}
    
        def f():
            a["name"] = "haha"
            pass
        return f
    
    
    code = g().__code__
    print(code.co_varnames)
    print(code.co_cellvars)
    print(code.co_freevars)  # ('a',)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
  • 相关阅读:
    计算机设计大赛 深度学习图像风格迁移 - opencv python
    CMake教程-第 1 步:基本起点
    LeetCode题练习与总结:统计词频--192
    Redis | 在Java中操作Redis
    mybatis-plus(mp)使用
    WEB三大主流框架之React
    Servlet入门
    FormData多个文件上传(fileList集合)
    [Vue2]实现点击下拉筛选table组件
    [东华杯2021] ezgadget
  • 原文地址:https://blog.csdn.net/u010376229/article/details/127837419