研究一种实现类f-string的方法

1. python中如何格式化字符串

python格式化化字符串有3种方法,分别是使用%,format, f-string, 从使用的便利性上讲,是逐个提高的,尤其是f-string,大大简化了字符串格式化代码的编写,下面的示例,是分别使用三种方式进行字符串格式化的操作示例

print("%s今年%d岁" % (name, age))
name = '李雷'
age = 14
print('{name}今年{age}岁'.format(name=name, age=age))
print(f'{name}今年{age}岁')

他们的格式化效果相同,最终结果都是

李雷今年14岁

使用f-string这种语法,显然代码更加简洁,这激发了我的兴趣,试一试,能否实现一个函数实现和f-string类似的效果。

我定义一个函数,并希望它能实现和f-string类似的效果

name = '李雷'
age = 14

def my_fstring(format_str):
    pass

string = my_fstring('{name}今年{age}岁')
print(string)   # 李雷今年14岁

2. 获得需要填充格式化的字段名称

想要实现上述的效果,首先,需要解析字符串,这里我使用正则表达式

import re

pattern = re.compile("{.*?}")

string = "{name}今年{age}岁"
result = pattern.findall(string)   # ['{name}', '{age}']
args = [item[1:-1] for item in result]  # ['name', 'age']

使用正则匹配,解析出字符串里有name和age需要被替换填充。

3. 获得name与age的值

尽管已经知道字符串在格式化时需要替换填充name和age,但怎么获取到这两个字段对应的值呢?这里我想到的方法是获取调用执行函数my_fstring时的frame, 通过frame的f_locals 来获得name与age

def my_fstring(format_str):
    pattern = re.compile("{.*?}")
    result = pattern.findall(format_str)  # ['{name}', '{age}']
    args = [item[1:-1] for item in result]

    frame = sys._getframe()
    f_back_frame = frame.f_back
    value_dict = {key: f_back_frame.f_locals.get(key) for key in args}
    return format_str.format(**value_dict)

在函数内部,通过sys模块,先获得当前的frame,随后通过f_back获得上一层的frame,上一层的frame里的f_locals属性就包含了name和age变量。最后,使用字符串的format方法对字符串进行格式化。

实现的my_fstring函数,还存在很多缺陷,不能代替,也没有必要代替f-string, 但这一次的研究过程,让你对python的函数调用有了更深入的理解和学习。

扫描关注, 与我技术互动

QQ交流群: 211426309

加入知识星球, 每天收获更多精彩内容

分享日常研究的python技术和遇到的问题及解决方案