Python字符串格式化:'%'比'format'函数更高效吗?

14 浏览
0 Comments

Python字符串格式化:'%'比'format'函数更高效吗?

我想要比较使用不同变量在Python中构建字符串的方法:

  • 使用+进行拼接(称为“加号”)
  • 使用%
  • 使用"".join(list)
  • 使用format函数
  • 使用"{0.}".format(object)

我比较了3种类型的场景:

  • 包含2个变量的字符串
  • 包含4个变量的字符串
  • 包含4个变量的字符串,每个变量使用两次

我对每种方法进行了100万次操作的测量,并对6次测量进行了平均。我得出了以下结果:

test_plus: 0.29480

test_percent: 0.47540

test_join: 0.56240

test_format: 0.72760

test_formatC: 0.90000

test_plus_long: 0.50520

test_percent_long: 0.58660

test_join_long: 0.64540

test_format_long: 1.03400

test_formatC_long: 1.28020

test_plus_long2: 0.95220

test_percent_long2: 0.81580

test_join_long2: 0.88400

test_format_long2: 1.51500

test_formatC_long2: 1.97160

在每种场景下,我得出了以下结论:

  • 拼接似乎是最快的方法之一
  • 使用%进行格式化比使用format函数要快得多

我认为format%要好得多(例如在这个问题中),而%几乎已经被弃用了。

因此,我有几个问题:

  1. %真的比format更快吗?
  2. 如果是这样,为什么会这样?
  3. "{} {}".format(var1, var2)"{0.attribute1} {0.attribute2}".format(object)更高效的原因是什么?

为了参考,我使用以下代码来测量不同的时间。

import time
def timing(f, n, show, *args):
    if show: print f.__name__ + ":\t",
    r = range(n/10)
    t1 = time.clock()
    for i in r:
        f(*args); f(*args); f(*args); f(*args); f(*args); f(*args); f(*args); f(*args); f(*args); f(*args)
    t2 = time.clock()
    timing = round(t2-t1, 3)
    if show: print timing
    return timing
class values(object):
    def __init__(self, a, b, c="", d=""):
        self.a = a
        self.b = b
        self.c = c
        self.d = d
def test_plus(a, b):
    return a + "-" + b
def test_percent(a, b):
    return "%s-%s" % (a, b)
def test_join(a, b):
    return ''.join([a, '-', b])
def test_format(a, b):
    return "{}-{}".format(a, b)
def test_formatC(val):
    return "{0.a}-{0.b}".format(val)
def test_plus_long(a, b, c, d):
    return a + "-" + b + "-" + c + "-" + d
def test_percent_long(a, b, c, d):
    return "%s-%s-%s-%s" % (a, b, c, d)
def test_join_long(a, b, c, d):
    return ''.join([a, '-', b, '-', c, '-', d])
def test_format_long(a, b, c, d):
    return "{0}-{1}-{2}-{3}".format(a, b, c, d)
def test_formatC_long(val):
    return "{0.a}-{0.b}-{0.c}-{0.d}".format(val)
def test_plus_long2(a, b, c, d):
    return a + "-" + b + "-" + c + "-" + d + "-" + a + "-" + b + "-" + c + "-" + d
def test_percent_long2(a, b, c, d):
    return "%s-%s-%s-%s-%s-%s-%s-%s" % (a, b, c, d, a, b, c, d)
def test_join_long2(a, b, c, d):
    return ''.join([a, '-', b, '-', c, '-', d, '-', a, '-', b, '-', c, '-', d])
def test_format_long2(a, b, c, d):
    return "{0}-{1}-{2}-{3}-{0}-{1}-{2}-{3}".format(a, b, c, d)
def test_formatC_long2(val):
    return "{0.a}-{0.b}-{0.c}-{0.d}-{0.a}-{0.b}-{0.c}-{0.d}".format(val)
def test_plus_superlong(lst):
    string = ""
    for i in lst:
        string += str(i)
    return string
def test_join_superlong(lst):
    return "".join([str(i) for i in lst])
def mean(numbers):
    return float(sum(numbers)) / max(len(numbers), 1)
nb_times = int(1e6)
n = xrange(5)
lst_numbers = xrange(1000)
from collections import defaultdict
metrics = defaultdict(list)
list_functions = [
    test_plus, test_percent, test_join, test_format, test_formatC,
    test_plus_long, test_percent_long, test_join_long, test_format_long, test_formatC_long,
    test_plus_long2, test_percent_long2, test_join_long2, test_format_long2, test_formatC_long2,
    # test_plus_superlong, test_join_superlong,
]
val = values("123", "456", "789", "0ab")
for i in n:
    for f in list_functions:
        print ".",
        name = f.__name__
        if "formatC" in name:
            t = timing(f, nb_times, False, val)
        elif '_long' in name:
            t = timing(f, nb_times, False, "123", "456", "789", "0ab")
        elif '_superlong' in name:
            t = timing(f, nb_times, False, lst_numbers)
        else:
            t = timing(f, nb_times, False, "123", "456")
        metrics[name].append(t) 
# Get Average
print "\n===AVERAGE OF TIMINGS==="
for f in list_functions:
    name = f.__name__
    timings = metrics[name]
    print "{:>20}:\t{:0.5f}".format(name, mean(timings))

0