为什么连接字符串比连接字符串运行得快?

2024-04-27 02:47:30 发布

您现在位置:Python中文网/ 问答频道 /正文

据我所知“.join(iterable_of_strings)是连接字符串的首选方式,因为它允许进行优化,避免将不可变对象重写到内存中的次数超过需要的次数。在

对我来说,在表达式中添加字符串比在中等数量的操作中连接它们运行得更快。在

在我的笔记本电脑上用python3.3运行这段代码,joined和added的时间分别为2.9-3.2秒和2.3-2.7秒。我在谷歌上找不到一个好答案。有人能解释一下可能发生的事情吗?或者告诉我一个好的资源吗?在

import uuid
import time

class mock:
    def __init__(self):
        self.name = "foo"
        self.address = "address"
        self.age = "age"
        self.primarykey = uuid.uuid4()

data_list = [mock() for x in range(2000000)]

def added():
    my_dict_list = {}
    t = time.time()
    new_dict = { item.primarykey: item.name + item.address + item.age for item in data_list }
    print(time.time() - t)

def joined():
    my_dict_list = {}
    t = time.time()
    new_dict = { item.primarykey: ''.join([item.name, item.address, item.age]) for item in data_list }
    print(time.time() - t)

joined()
added()

Tags: nameinselfaddedforagedatatime
2条回答

As I understand it "".join(iterable_of_strings) is the preferred way to concatenate strings because it allows for optimizations that avoid having to rewrite the immutable object to memory more times than necessary.

你理解得有点不正确。"".join(iterable_of_strings)是连接字符串的iterable的首选方法,正如您所解释的那样。在

但是,你没有一个字符串。你只有三根弦。连接三个字符串的最快方法是将它们与+相加,或者使用.format()或{}。在这种情况下,首先要避免复制所有的字符串,因为首先要避免复制字符串。在

.join()不会变得更快,除非你有太多的字符串,这会导致愚蠢的代码使用其他方法。何时发生取决于您使用的Python实现、什么版本以及字符串的长度,但是我们通常讨论的是超过10个字符串。在

虽然并不是所有的实现都有快速的连接,但是我测试了CPython、PyPy和Jython,并且它们都有更快的连接速度,或者只对几个字符串进行连接。在

实际上,您应该在+.join()之间进行选择,这取决于代码的清晰度,直到代码运行为止。然后,如果你关心速度:分析和测试你的代码。不要坐在那里瞎猜。

一些计时:http://slides.colliberty.com/DjangoConEU-2013/#/step-40

带视频说明:http://youtu.be/50OIO9ONmks?t=18m30s

您看到的时间差来自创建要传递给join的列表。虽然使用元组可以获得一个小的加速,但是当只有几个短字符串时,它仍然比仅仅用+连接要慢。在

如果以字符串的iterable开头,而不是以字符串作为属性的对象,则会有所不同。然后您可以直接在iterable上调用join,而不必为每次调用构建一个新的。在

下面是我对timeit模块进行的一些测试:

import timeit

short_strings = ["foo", "bar", "baz"]
long_strings = [s*1000 for s in short_strings]

def concat(a, b, c):
    return a + b + c

def concat_from_list(lst):
    return lst[0] + lst[1] + lst[2]

def join(a, b, c):
    return "".join([a, b, c])

def join_tuple(a, b, c):
    return "".join((a, b, c))

def join_from_list(lst):
    return "".join(lst)

def test():
    print("Short strings")
    print("{:20}{}".format("concat:",
                           timeit.timeit(lambda: concat(*short_strings))))
    print("{:20}{}".format("concat_from_list:",
                           timeit.timeit(lambda: concat_from_list(short_strings))))
    print("{:20}{}".format("join:",
                           timeit.timeit(lambda: join(*short_strings))))
    print("{:20}{}".format("join_tuple:",
                           timeit.timeit(lambda: join_tuple(*short_strings))))
    print("{:20}{}\n".format("join_from_list:",
                             timeit.timeit(lambda: join_from_list(short_strings))))
    print("Long Strings")
    print("{:20}{}".format("concat:",
                           timeit.timeit(lambda: concat(*long_strings))))
    print("{:20}{}".format("concat_from_list:",
                           timeit.timeit(lambda: concat_from_list(long_strings))))
    print("{:20}{}".format("join:",
                           timeit.timeit(lambda: join(*long_strings))))
    print("{:20}{}".format("join_tuple:",
                           timeit.timeit(lambda: join_tuple(*long_strings))))
    print("{:20}{}".format("join_from_list:",
                           timeit.timeit(lambda: join_from_list(long_strings))))

输出:

^{pr2}$

所以,从已经存在的列表中加入总是最快的。如果单个项很短,用+连接会更快,但对于长字符串,则总是最慢的。我怀疑concatconcat_from_list之间的区别来自于测试代码中函数调用中列表的解包。在

相关问题 更多 >