python优化函数而不循环

时间:2014-01-17 19:29:01

标签: python performance

我有一个基本的“餐巾算法”,它采用元组列表(包含2个项目)并更改它们。这是英文版:

  1. 如果第2项是列表,则将第1项更改为字符串x
  2. 否则将第1项更改为字符串y
  3. 这是我放在一起的快速功能:

    def f(objects):
        list_type = "string_x"
        other = "string_y"
        hold = []
        for x in objects:
            if isinstance(x[1],list):
                hold.append((list_type,x[1]))
            else:
                hold.append((other,x[1]))
        return hold
    

    我不相信这是最有效的方式。该算法非常简单,只是一个基本的陈述。 这样做的效率更高?

4 个答案:

答案 0 :(得分:2)

您可以使用if表达式将其缩短一点:

def f(objects):
    list_type = "string_x"
    other = "string_y"
    hold = []
    for x in objects:
        hold.append((list_type if isinstance(x[1], list) else other, x[1]))
    return hold

然后很容易变成一种理解,这种理解甚至更短,可能更具可读性,更快一点:*

def f(objects):
    list_type = "string_x"
    other = "string_y"
    return [(list_type if isinstance(x[1], list) else other, x[1]) 
            for x in objects]

实际上,我不确定那些局部变量是否使事情变得更清楚:**

def f(objects):
    return [("string_x" if isinstance(x[1], list) else "string_y", x[1]) 
            for x in objects]

同时,如果你要对返回的列表做的唯一事情就是迭代它(例如,因为这只是一个转换链中的一个),你根本不应该返回一个列表。每个值yield,返回genexpr而不是listcomp,或者(如果你有Python 3.3+)获得两全其美:

def f(objects):
    yield from (("string_x" if isinstance(x[1], list) else "string_y", x[1]) 
                for x in objects)

*您仍在执行完全相同的循环,因此您具有完全相同的算法复杂度。但是,循环和列表追加都发生在自定义字节码中,这些字节码采用了一些快捷方式,使每次迭代更有效。 (“自定义字节码”详细信息当然特定于CPython和其他字节码兼容的实现,如PyPy,但一般来说,任何实现至少都可以采用列表推导的快捷方式。)

**最后这个可能会稍快一些,因为它将一个常量加载到堆栈而不是局部变量。然后,它可能也有稍微更糟糕的缓存局部性。如果真的很重要,请测试并查看。

答案 1 :(得分:0)

使用列表理解会更有效率和 pythonic (如果我没错):

[("string_x" if isinstance(x[1], list) else "string_y", x[1]) for x in objects]

答案 2 :(得分:0)

如果您需要检查并更改列表中的所有项目,则需要循环,否则您无法执行此操作。

你可以使用列表理解使其快一点,这减少了每个列表项的追加功能。

def f(objects):
    return [('string_x',x[1]) if isinstance(x[1],list) else ('string_y',x[1]) for x in objects]

但只有在使用大型列表

时才会看到性能差异

答案 3 :(得分:0)

我有点像这样做,但我可能是一个愚蠢的人:

strings = 'string_x', 'string_y'

[(strings[isinstance(x[1],list)], x[1]) for x in objects]