Python函数每次被调用时都会重新声明文档字符串吗
核心结论
首先给准话:按照Python官方规范写的标准文档字符串,完全不会在每次函数调用时重复创建。
Python处理def语句的逻辑是:执行到def关键字定义函数时,解释器会检查函数体的第一条语句是不是字符串字面量,如果是,就直接把这个字符串绑定到当前生成的函数对象的__doc__属性上,之后编译函数字节码的时候,会直接把这条字符串语句从执行流里删掉。后续不管你调用这个函数多少次,执行的字节码里根本没有和docstring相关的逻辑,连碰都不会碰这个字符串,不存在重复声明、重复创建的开销。
你可以自己用dis模块反汇编验证:写完一个带标准docstring的函数,用dis.dis(你的函数名)看字节码,会发现第一条执行指令直接对应你写的第一行业务逻辑,根本没有加载docstring的相关操作。
唯一会产生重复创建开销的错误写法
只有当你没按规范写docstring的时候,才会出现每次调用重复生成字符串的问题,典型错误场景:
- 把字符串字面量写在函数体非第一行的位置,这种字符串根本不会被识别为docstring,只是一个无意义的表达式语句,每次函数调用都会重新创建这个字符串对象,求值之后直接丢弃,纯纯浪费性能。
- 动态生成函数时,错误地在函数体内部通过赋值语句给
__doc__赋值:注意函数体内部直接写__doc__ = "xxx"是给局部变量赋值,根本改不了函数对象的__doc__属性,属于写了也白写还费性能的操作。 - 给lambda表达式硬塞字符串当docstring:lambda的函数体只能是单个表达式,你就算在表达式开头写字符串,也只是每次调用都会执行的普通表达式,不会绑定到
__doc__属性。
零开销docstring实现方案
根本不需要什么奇技淫巧,按下面的规则写就能完全避免重复开销,同时正常通过__doc__访问文档:
- 普通静态定义的函数:老老实实把docstring写在
def语句下、函数体的第一行,这是官方原生支持的零开销方案,定义时一次绑定,调用时无任何额外成本。 - 批量动态生成函数的场景:提前把公共docstring定义成全局/外层作用域的常量,等内部函数定义完成后,直接把这个常量赋值给函数对象的
__doc__属性即可,参考示例:
# 公共docstring只在模块加载时创建一次,全量复用 _COMMON_CALC_DOC = """接收数值输入,返回计算后的结果 参数: x: 输入的整数/浮点数 返回: 计算后的数值 """ def calc_func_generator(multiplier): def calc(x): return x * multiplier # 直接绑定公共docstring,函数调用时无任何额外开销 calc.__doc__ = _COMMON_CALC_DOC return calc
这种写法下,不管生成多少个calc函数,docstring在内存里只有一份,调用任何一个calc函数的时候都不会触发字符串创建逻辑,性能和静态写死docstring的函数完全一致。
- 额外提醒:函数内部的说明性注释一律用
#写,不要用孤立的三引号字符串,避免产生无效运行时开销。
内容的提问来源于stack exchange,提问作者artils1997
相关产品推荐
相关产品推荐

