Chr*_*els 6 python string loops concatenation f-string
我正在使用 timeit 对项目的一些代码进行基准测试(使用免费的 replit,因此需要 1024MB 内存):
\ncode = \'{"type":"body","layers":[\'\n\nfor x, row in enumerate(pixels):\n for y, pixel in enumerate(row):\n if pixel != (0, 0, 0, 0):\n code += f\'\'\'{{"offsetX":{-start + x * gap},"offsetY":{start - y * gap},"rot":45,"size":{size},"sides":4,"outerSides":0,"outerSize":0,"team":"{\'#%02x%02x%02x\' % (pixel[:3])}","hideBorder":1}},\'\'\'\n \ncode += \'],"sides":1,"name":"Image"}}\nRun Code Online (Sandbox Code Playgroud)\n该循环针对给定图像内的每个像素运行(当然效率不高,但我还没有实现任何减少循环时间的方法),因此我可以在循环中获得的任何优化都是值得的。
\n我记得只要你组合 3 个以上的字符串\xe2\x80\x94,f 字符串就比字符串连接更快,如图所示,我组合了超过3个字符串\xe2\x80\x94,所以我决定将循环内的 += 替换为 f 字符串并查看改进。
\ncode = \'{"type":"body","layers":[\'\n\nfor x, row in enumerate(pixels):\n for y, pixel in enumerate(row):\n if pixel != (0, 0, 0, 0):\n code = f\'\'\'{code}{{"offsetX":{-start + x * gap},"offsetY":{start - y * gap},"rot":45,"size":{size},"sides":4,"outerSides":0,"outerSize":0,"team":"{\'#%02x%02x%02x\' % (pixel[:3])}","hideBorder":1}},\'\'\'\n \ncode += \'],"sides":1,"name":"Image"}}\nRun Code Online (Sandbox Code Playgroud)\n500次timeit迭代的结果:
\n+= took 5.399778672000139 seconds\nfstr took 6.91279206800027 seconds\nRun Code Online (Sandbox Code Playgroud)\n我已经重新运行了多次;以上次数是迄今为止 f 弦所做的最好的次数。为什么在这种情况下 f 字符串速度较慢?
\nPS:这是我第一次在这里发帖提问。任何有关如何改进我未来问题的建议将不胜感激:D
\n因此,首先,理论上,具有不可变字符串的语言中的重复串联是O(n\xc2\xb2),而有效实现的批量串联是O(n),因此从理论上讲,这两个版本的代码都不适合重复串联。适用于任何地方的工作版本O(n)是:
code = [\'{"type":"body","layers":[\'] # Use list of str, not str\n\nfor x, row in enumerate(pixels):\n for y, pixel in enumerate(row):\n if pixel != (0, 0, 0, 0):\n code.append(f\'\'\'{{"offsetX":{-start + x * gap},"offsetY":{start - y * gap},"rot":45,"size":{size},"sides":4,"outerSides":0,"outerSize":0,"team":"{\'#%02x%02x%02x\' % (pixel[:3])}","hideBorder":1}},\'\'\') # Append each new string to list\n \ncode.append(\'],"sides":1,"name":"Image"}}\')\ncode = \'\'.join(code) # Efficiently join list of str back to single str\nRun Code Online (Sandbox Code Playgroud)\n您的代码+=恰好能够足够高效地工作,因为在连接到没有其他活动引用的字符串时,CPython 对字符串连接进行了特定的优化,但 PEP8 风格指南中的第一个编程建议特别警告不要依赖它:
\n\n\n
a += b...不要依赖 CPython\xe2\x80\x99s 有效实现或形式的语句的就地字符串连接a = a + b。即使在 CPython 中,这种优化也是脆弱的(它仅适用于某些类型),并且在不使用引用计数的实现中根本不存在 xe2x80x99。在库的性能敏感部分,\'\'.join()应改用表单。这将确保在各种实现中串联在线性时间内发生。
本质上,基于原始的+=代码受益于优化,因此最终执行的数据副本更少。基于 f 字符串的代码做了相同的工作,但在某种程度上阻止了 CPython 优化的应用(str 每次都构建一个全新的、越来越大的)。这两种方法的形式都很糟糕,其中一种在 CPython 上的表现稍微好一些。当您的热代码执行重复串联时,您已经在做错误的事情,只需在末尾使用listofstr和即可。\'\'.join
| 归档时间: |
|
| 查看次数: |
576 次 |
| 最近记录: |