引入
看一段python代码,打印一个函数的__code__,返回的是一个code object,code object是什么,有哪些属性呢?
def f():
pass
f.__code__
<code object f at 0x00000176FC4E8B30, file "<input>", 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']
code object的各个属性的含义可以参考官方文档code object属性含义
co_argcount | number of arguments (not including keyword only arguments, * or ** args) |
---|---|
co_code | string of raw compiled bytecode |
co_cellvars | tuple of names of cell variables (referenced by containing scopes) |
co_consts | tuple of constants used in the bytecode |
co_filename | name of file in which this code object was created |
co_firstlineno | number of first line in Python source code |
co_flags | bitmap of CO_* flags, read more here |
co_lnotab | encoded mapping of line numbers to bytecode indices |
co_freevars | tuple of names of free variables (referenced via a function’s closure) |
co_posonlyargcount | number of positional only arguments |
co_kwonlyargcount | number of keyword only arguments (not including ** arg) |
co_name | name with which this code object was defined |
co_qualname | fully qualified name with which this code object was defined |
co_names | tuple of names other than arguments and function locals |
co_nlocals | number of local variables |
co_stacksize | virtual machine stack space required |
co_varnames | tuple 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 虚拟机需要的栈空间
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)
函数定义时可以用‘/’划分,将’/'前面的规定全为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'
同时还可以用‘‘划分,’'后面的全部都是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
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') 出现的常量如数字,字符串
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)
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)
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',)