循环外定义Python f-string为何输出重复值?
问题:循环外定义f-string导致输出重复值?
我想定义包含变量的格式字符串,比如MYSTRING = f"filepath/{year}/{month}",但在循环外定义该变量时,循环输出的结果全是重复值;把字符串移到循环内定义则运行正常。
正常运行的代码:
from datetime import date last_n_months = 12 months = date.today().year * 12 + date.today().month - 1 # 从公元0年开始计算的月份数减1 tuples = [((months - i) // 12, (months - i) % 12 + 1) for i in range(last_n_months)] for item in tuples: year = str(item[0]) month = str(item[1]) # 直接在循环内使用f-string print(f"xyz/Year={year}/Month={month}")
输出结果:
xyz/Year=2024/Month=11 xyz/Year=2024/Month=10 xyz/Year=2024/Month=9 xyz/Year=2024/Month=8 xyz/Year=2024/Month=7 xyz/Year=2024/Month=6 xyz/Year=2024/Month=5 xyz/Year=2024/Month=4 xyz/Year=2024/Month=3 xyz/Year=2024/Month=2 xyz/Year=2024/Month=1 xyz/Year=2023/Month=12
输出重复值的代码:
from datetime import date # 在循环外定义f-string myformatstring = f"xyz/Year={year}/Month={month}" last_n_months = 12 months = date.today().year * 12 + date.today().month - 1 # 从公元0年开始计算的月份数减1 tuples = [((months - i) // 12, (months - i) % 12 + 1) for i in range(last_n_months)] for item in tuples: year = str(item[0]) month = str(item[1]) # 使用循环外定义的字符串变量 print(myformatstring)
输出结果:
xyz/Year=2023/Month=12 xyz/Year=2023/Month=12 xyz/Year=2023/Month=12 xyz/Year=2023/Month=12 xyz/Year=2023/Month=12 xyz/Year=2023/Month=12 xyz/Year=2023/Month=12 xyz/Year=2023/Month=12 xyz/Year=2023/Month=12 xyz/Year=2023/Month=12 xyz/Year=2023/Month=12 xyz/Year=2023/Month=12
原因分析:
f-string的核心特性是即时求值——当你定义f"xyz/Year={year}/Month={month}"时,Python会立刻将定义时刻year和month的当前值代入字符串,生成一个固定的静态字符串。
在第二段代码中,循环外定义myformatstring时,year和month要么是之前运行代码残留的最后一组值(比如2023/12),要么首次运行会直接报错。但不管怎样,一旦myformatstring被定义,它就变成了固定字符串,后续循环中修改year和month的值不会对它产生任何影响,所以每次输出都是同一个结果。
而在循环内定义f-string时,每次循环都会重新执行f-string的求值逻辑,用当前循环迭代的year和month生成新的字符串,因此输出正常。
解决方法:
如果想在循环外定义可复用的模板,不要用f-string,改用以下两种方式:
- 使用str.format()的模板字符串:
from datetime import date # 定义带占位符的模板 myformatstring = "xyz/Year={year}/Month={month}" last_n_months = 12 months = date.today().year * 12 + date.today().month - 1 tuples = [((months - i) // 12, (months - i) % 12 + 1) for i in range(last_n_months)] for item in tuples: year = str(item[0]) month = str(item[1]) # 循环内传入参数格式化 print(myformatstring.format(year=year, month=month))
- 用lambda封装延迟求值:
from datetime import date # 用lambda封装f-string的生成逻辑,延迟到调用时求值 myformatstring = lambda year, month: f"xyz/Year={year}/Month={month}" last_n_months = 12 months = date.today().year * 12 + date.today().month - 1 tuples = [((months - i) // 12, (months - i) % 12 + 1) for i in range(last_n_months)] for item in tuples: year = str(item[0]) month = str(item[1]) # 调用lambda生成字符串 print(myformatstring(year, month))
内容的提问来源于stack exchange,提问作者mateoc15
相关产品推荐
相关产品推荐

