Python 3.8 f-string调试新功能:使用=简化变量追踪
Python 3.8引入了f-string的调试功能,允许在格式化字符串中直接使用=后缀自动输出变量名及其值。相比传统的print调试,这种方式无需手动拼接变量名,支持表达式求值及与转换标志(!r, !s, !a)组合使用,显著提升了代码调试的清晰度与效率。
前言
前言
传统print调试的局限性
在日常开发中,我约98%的情况依赖print语句进行调试(诸如pdb等工具在实际工作中往往不够实用)。通过在关键位置插入print语句,打印出需要跟踪的表达式或变量值,从而定位问题。虽然f-string让字符串格式化变得简洁美观,但在调试场景下,它并未提供额外的便利。
以下是一个具体示例:
s = 'A string'
value = 123
若需查看运行时变量s和value的具体数值(注:此处演示的是常量,实际代码中它们可能是动态计算出的表达式或函数调用结果),可以在代码中插入一行print语句进行打印:
s = 'A string'
value = 123
print(s, value) # 新插入的行
通过日志或终端输出,即可获知s和value的值。然而,这种方式的缺陷在于,仅输出变量值无法明确指示该输出源自代码的哪一行;若代码中存在多个print语句,且每个语句均包含两个参数,排查起来将十分繁琐:
s = 'A string'
value = 123
print(s, value)
o = 'Other String'
rv = 234
print(o, rv) # 另外一个print
此时,必须借助某种方法来区分这些输出分别来自代码的哪一行:
s = 'A string'
value = 123
print(s, value, 'S')
o = 'Other String'
rv = 234
print(o, rv, 'Other')
这是我常用的解决方案:在print中添加第三个参数,利用该参数标识输出来源的行号或上下文。
良好的调试写法应清晰展示被跟踪变量与其值的对应关系。参考如下写法:
>>> print(f's={s!r}, value={value}')
s='A string', value=123
>>> print(f'o={o!r}, rv={rv}')
o='Other String', rv=234
在大括号内部,除了变量名外,还可以添加!r转换标志(conversion flag),这在旧的format格式化方法中同样存在。共有三种转换标志,另外两种为!a和!s,具体效果如下:
>>> '{!a}'.format('哈哈') # 相当于 ascii('哈哈')
"'\\u54c8\\u54c8'"
>>> '{!s}'.format('哈哈') # 相当于 str('哈哈')
'哈哈'
>>> '{!r}'.format('哈哈') # 相当于 repr('哈哈')
"'哈哈'"
在上述示例中,{s!r}的作用等同于对变量s执行str(s)操作(尽管通常不建议这样书写,因为!r实际对应repr):
>>> print(f's={s}')
s=A string # 注意,没有引号,空格把值分开了,有多个值的话就不容易辨识
>>> print(f's="{s}"') # 不用`!r`需要手动加引号
s="A string"
无论如何,这种写法已经算是不错的改进,但当需要打印的变量较多时,print语句会变得非常冗长……
Python 3.8 f-string的'='调试功能
Python 3.8中f-string的'='功能
这一功能源自PyCON 2019的一场闪电演讲。f-string的作者Eric V. Smith采纳了Larry Hastings的建议,实现了f-string的调试特性。最初计划使用另一个转换标识!d,效果大致如下:
value = 10
s = 'a string!'
print(f'{value!d}')
print(f'next: {value+1!d}')
print(f'{s!d}')
print(f'{s!d:*^20}')
print(f'*{value!d:^20}*')
# 输出
value=10
next: value+1=11
s='a string!'
'****s="A string"****'
* value=10 *
这意味着f-string会自动添加“变量名 + =”,同时支持补齐空位及表达式求值。例如,{value+1!d}表示先计算value+1,再将其结果打印出来。
随后,作者与Guido van Rossum讨论后,决定采用更灵活的=符号。该功能现已合并至Python 3.8,我们可以实际体验:
❯ ./python.exe
Python 3.8.0a4+ (heads/master:2725cb01d7, May 22 2019, 10:29:22)
...
>>> print(f'{s=}, {value=}')
s='A string', value=123
>>> print(f'{o=}, {rv=}')
o='Other String', rv=234
>>> print(f'{value / 3 + 15=}')
value / 3 + 15=56.0
>>> print(f'{s=:*^20}')
s=******A string******
>>> print(f'*{s=:^20}*')
*s= A string *
为何说使用=更灵活?请看几个结合转换标志的示例:
>>> x = '哈哈'
>>> f'{x=}'
"x='哈哈'"
>>> f'{x=!s}'
'x=哈哈'
>>> f'{x=!r}'
"x='哈哈'"
>>> f'{x=!a}'
"x='\\u54c8\\u54c8'"
>>> f'{x=!s:^20}'
'x= 哈哈 '
这表明,调试模式可以与转换标志配合使用!
你是否学到了新技巧?开始期待Python 3.8的正式发布吧~
注:如果你观看了PyCON的“Easier debugging with f-string”演讲(延伸阅读链接2),其中仍提及使用!d,但实际上在演讲结束后的第二天,方案已更改为=,请注意这一变化。
总结
以上介绍了Python 3.8中利用f-string进行调试的方法,希望对大家有所帮助。如有任何疑问,欢迎留言,小编会及时回复!
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













