修改字符串模板以使用其他变量作为修饰符

Modifying a string template to use other variables as modifiers

我正在做一个助手 class 来简化基准测试循环,它包含 timing it's entire execution and each user defined amount of iterations:

import time

class LoopTimer:
    @staticmethod
    def run(fn, start, end, step = 1, batch_size = 1, precision = 8, 
            template = 'iteration = {current_iteration} \t took {batch_elapsed_time:.8f}s \t total = {total_elapsed_time:.8f}s \t value = {value}'):
        counter, counter_total = time.process_time(), time.process_time()
        for i in range(start, end, step):
            value = fn(i)
            if i > 0 & i % batch_size == 0:
                end = time.process_time()
                print(template.format_map({
                    'current_iteration':i,
                    'batch_elapsed_time': end-counter,
                    'total_elapsed_time': end-counter_total,
                    'value': value,
                    'batch_start': counter,
                    'batch_end': end,
                    'loop_start': counter_total
                }))
                counter = time.process_time()

用户如何能够定义 LoopTimer.precision 以便无需创建新模板来限制当前的浮点精度 (8)?当然,可以通过像这样预格式化字符串来实现:

template = 'iteration = {current_iteration} \t took {batch_elapsed_time:.*precision1*f}s \t total = {total_elapsed_time:.*precision2*f}s \t value = '
print(template.replace('*precision1*', '1').replace('*precision2*', '9').format_map({
    'current_iteration':i,
    'batch_elapsed_time': end-counter,
    'total_elapsed_time': end-counter_total,
    'value': value,
    'batch_start': counter,
    'batch_end': end,
    'loop_start': counter_total
}))

但在看到 str.format 功能后感觉有点脏。


编辑

格式化时也有一个奇怪的行为(使用上面定义的模板):

iteration = 97   took 0.00000000s        total = 0.00000000s     value = 158456325028528675187087900672
iteration = 98   took 0.00000000s        total = 0.00000000s     value = 316912650057057350374175801344
iteration = 99   took 0.00000000s        total = 0.00000000s     value = 633825300114114700748351602688
iteration = 100          took 0.00000000s        total = 0.00000000s     value = 1267650600228229401496703205376
iteration = 101          took 0.00000000s        total = 0.00000000s     value = 2535301200456458802993406410752
iteration = 102          took 0.00000000s        total = 0.00000000s     value = 5070602400912917605986812821504

如何解决这个问题?

允许一级嵌套格式,因此您可以将模板更改为:template = 'iteration = {current_iteration} took {batch_elapsed_time:.{precision}f}s total = {total_elapsed_time:.{precision}f}s value = {value}',然后在 format_map().

中添加 'precision': precision

\t长度不固定,插入空格使当前子串8个字符宽,然后转到下一个子串。比如print("1\t23\t456\t7890")的输出是
1 23 456 78901后接7个空格\t23后接6个空格\t456后接5个空格\t,每个子串都是8个字符宽。因此,我在模板中使用固定的6个空格。

测试 运行 LoopTimer.run(lambda i: 2 ** i, 97, 103, precision = 4):

iteration = 97      took 0.0000s      total = 0.0000s      value = 158456325028528675187087900672
iteration = 98      took 0.0000s      total = 0.0000s      value = 316912650057057350374175801344
iteration = 99      took 0.0000s      total = 0.0000s      value = 633825300114114700748351602688
iteration = 100      took 0.0000s      total = 0.0000s      value = 1267650600228229401496703205376
iteration = 101      took 0.0000s      total = 0.0000s      value = 2535301200456458802993406410752
iteration = 102      took 0.0000s      total = 0.0000s      value = 5070602400912917605986812821504