F字符串或如何使代码更快,更易读



Python有3种格式化字符串的方式,其中一种优于其他方式。 但是,让我们不要超越自己-我们在谈论哪种格式? 每次我们要按名称向用户打招呼时,都需要在模板字符串中插入一个带有名称的字符串。 最有用的日志条目还包含变量值。 这是一个示例:

integer = 42 string = 'FORTY_TWO' print('string number %s, or simply %d' % (string, integer)) print('string number {}, or simply {}'.format(string, integer)) print(f'string number {string}, or simply {integer}') 

第一种使用%运算符进行格式化的方法来自C语言的Python-它模仿了printf函数。 此方法是python中的第一个方法,并且在Python 2.5及以下版本中仍然是唯一的方法(在本文中进行了讨论)。

第二种方法是str.format方法,它属于内置字符串类。 它带有Python 3.0,并已移植到2.6版。 已推荐此方法具有更丰富的语法。

第三种方法f字符串出现在Python 3.6版中。 如PEP-0498中所述,创建新的格式化字符串的方法是由于现有方法的缺点而引起的,作者将这些方法描述为易于出错,不够灵活且不够优雅:
这个PEP是由渴望拥有一种更简单的Python格式化字符串格式的愿望所驱动的。 现有的格式化方式容易出错,不灵活或麻烦。
因此,我们有三种方法来解决一个问题。 但这可能是个人喜好和偏好的问题吗? 也许可以,但是您的代码样式(尤其是具有大量参与者的项目中的代码)肯定会受益于统一性。 在最好的情况下,您应该使用一种格式化字符串的方法,这将使阅读代码变得更加容易。 但是选择哪种方法呢? 代码性能是否有所不同?

让我们尝试通过实验回答有关性能的问题:

 import timeit setup = """ integer = 42 string = 'FORTY_TWO' """.strip() percent_stmt ="'Number %s or simply %d' % (string, integer)" call_stmt = "'Number {} or simply {}'.format(string, integer)" fstr_stmt = """f'Number {string} or simply {integer}'""" def time(stmt): return f"{timeit.timeit(stmt, setup, number=int(1e7)):.3f}" print(f"Timing percent formating: | {time(percent_stmt)}") print(f"Timing call formating: | {time(call_stmt)}") print(f"Timing f-string formating: | {time(fstr_stmt)}") 

带有Python 3.7的MacBook上的结果:

 Timing percent formating: | 2.025 Timing call formating: | 2.943 Timing f-string formating: | 1.348 

差异是显着的。 那么,现在在“ .format”上运行正则表达式搜索并重写数百个表达式吗? 原则上,该任务很简单但是很耗时。 加上犯错的机会,并在以前可以正常运行的代码中添加错误! 似乎还有自动化的空间。 确实,有些库可以将大多数表达式转换为f字符串: flyntpyupgrade

Flynt易于使用。 例如,对烧瓶源代码运行转换:

 38f9d3a65222:~ ikkamens$ git clone https://github.com/pallets/flask.git Cloning into 'flask'... ... Resolving deltas: 100% (12203/12203), done. 38f9d3a65222:~ ikkamens$ flynt flask Flynt run has finished. Stats: Execution time: 0.623s Files modified: 18 Expressions transformed: 43 Character count reduction: 241 (0.04%) _-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_. Please run your tests before commiting. Report bugs as github issues at: https://github.com/ikamensh/flynt Thank you for using flynt! Fstringify more projects and recommend it to your colleagues! _-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_._-_. 38f9d3a65222:~ ikkamens$ 

还值得注意的是,可能会转换占用几行的表达式,并收集有关所做更改的统计信息。 标志--line_length XX定义转换后的行长度限制。 Flynt允许您使用--upgrade标志调用pyupgrade。

Pyupgrade包含更多功能,并且可以清除许多Python 2构件中的代码-例如从对象继承,以super指定类名, 等等 。 Pyupgrade设计用于pre-commitpre-commit是在提交之前自动修改代码的实用程序。

最好在gita或其他版本控件中转换源。 值得运行测试并亲自查看更改(使用git diff或PyCharm环境)。 只要我们生活在关心的人中,即代码已经缩短了几个字符,主动转换也将节省他们的时间。 毕竟,迟早有人会开始动手做实用程序。 F字符串仅在Python 3.6+上有效,但是不久之后这将不再是问题,因为其他版本将会过时

值得注意的是,经典的.format方法无法完全解决。 如果您使用相同的模板在代码中的不同位置创建带有不同变量的消息,则应将此模板保存在变量中并使用它-“不要重复自己”的原理比从格式化字符串中获得十亿分之一秒的重要性更为重要。

结论:

我们查看了Python 3.6+中可用的三种字符串格式化方法,它们的简要历史,并比较了它们的性能。 我们还研究了用于将代码自动转换为用于格式化字符串的新方法的开源工具及其附加功能。 不要忘记代码中的简单内容,祝您好运!

Source: https://habr.com/ru/post/zh-CN462179/


All Articles