使用字符串方法的functools.partial替代方案

1 投票
1 回答
1695 浏览
提问于 2025-04-18 16:40

我的代码分析显示,str对象的splitstrip方法是被调用次数最多的函数之一。

我使用了一些这样的代码:

with open(filename, "r") as my_file:
    for line in my_file:
        fields = line.strip("\n").split("\t")

而且,有些文件的行数非常多。

所以我尝试按照这个链接里的建议,尽量避免使用点(即方法调用),如下所示:

from functools import partial
split = str.split
tabsplit = partial(split, "\t")
strip = str.strip
endlinestrip = partial(strip, "\n")
def get_fields(tab_sep_line):
    return tabsplit(endlinestrip(tab_sep_line))

with open(filename, "r") as my_file:
    for line in my_file:
        fields = getfields(line)

然而,这导致我的get_fields函数在return这一行出现了ValueError: empty separator的错误。

经过调查,我了解到split方法的分隔符是第二个参数,第一个参数是字符串对象本身。这让functools.partial"\t"理解成了要被分割的字符串,而我使用"\n".strip(tab_sep_line)的结果作为分隔符。因此出现了错误。

你有什么建议可以替代这个做法吗?


编辑:我尝试比较了三种实现get_fields函数的方法。

方法一:使用普通的.strip.split

def get_fields(tab_sep_line):
    return tab_sep_line.strip("\n").split("\t")

方法二:使用lambda

split = str.split
strip = str.strip
tabsplit = lambda s : split(s, "\t")
endlinestrip = lambda s : strip(s, "\n")
def get_fields(tab_sep_line):
    return tabsplit(endlinestrip(tab_sep_line))

方法三:使用Jason S提供的答案

split = str.split
strip = str.strip
def get_fields(tab_sep_line):
    return split(strip(tab_sep_line, "\n"), "\t")

分析结果显示,get_fields的累计时间如下:

方法一:13.027

方法二:16.487

方法三:9.714

所以,避免使用点确实有区别,但使用lambda似乎是得不偿失。

1 个回答

3

关于“避免使用点(.)”来提高性能的建议,其实有两个要点:第一,只有在你真的遇到性能问题的时候才需要考虑这个问题,也就是说,不是因为某个东西被调用很多次就一定要担心,而是要看它是否真的“耗时过长”;第二,使用partial并不能解决这个问题。

之所以使用点的操作会比使用局部变量慢,是因为每次使用点的时候,Python都需要去查找这个属性。但如果你使用partial,那么每次调用时不仅会多一次函数调用,还会每次都复制和更新一个字典,并且还要添加两个列表。这样做其实是得不偿失,反而会更慢。

不过,如果你真的想这么做,可以试试:

strip = str.strip
split = str.split
...
fields = split(strip(line), '\t')

撰写回答