繁体   English   中英

Python:多次创建一个小列表有多贵?

[英]Python: How expensive is to create a small list many times?

我在Python中一遍又一遍地遇到以下小烦恼的困境:

选项1:

如果多次调用,因为为每次调用do_something()重新创建a_list,所以更干净但更慢(?)

def do_something():    
  a_list = ["any", "think", "whatever"]    
  # read something from a_list

选项2:

更丑但更有效率(重新创建a_list创建)

a_list = ["any", "think", "whatever"]    
def do_something():    
  # read something from a_list

你怎么看?

它有什么难看的?

列表的内容是否始终是常量,如示例中所示? 如果是这样的话:Python的最新版本(从2.4开始)将通过评估常量表达式并保持结果来优化它,但前提是它只是一个元组。 所以你可以把它变成一个元组。 或者你可以不再担心那样的小事。

这是一个常量列表和一个常量元组:

>>> def afunc():
...    a = ['foo', 'bar', 'zot']
...    b = ('oof', 'rab', 'toz')
...    return
...
>>> import dis; dis.dis(afunc)
  2           0 LOAD_CONST               1 ('foo')
              3 LOAD_CONST               2 ('bar')
              6 LOAD_CONST               3 ('zot')
              9 BUILD_LIST               3
             12 STORE_FAST               0 (a)

  3          15 LOAD_CONST               7 (('oof', 'rab', 'toz'))
             18 STORE_FAST               1 (b)

  4          21 LOAD_CONST               0 (None)
             24 RETURN_VALUE
>>>

如果你不需要,不要创造多于一次的东西。 这是一个简单的优化,可以在你的部分完成,我个人并不觉得第二个例子是丑陋的。

有些人可能会争辩不要担心优化这样的小事情,但我觉得应该立即完成这个简单的修复。 我不愿意看到你的应用程序创建了多个副本,它们不需要简单地保留任意“代码美”。 :)

选项3:

def do_something(a_list = ("any", "think", "whatever")):
    read something from a_list

备选方案3与备选方案1相比:

在我看来,两者都具有相同的可读性(尽管有些人在评论中似乎有不同的想法!:-))。 你甚至可以像这样编写选项3

def do_something(
    a_list = ("any", "think", "whatever")):
    read something from a_list

这实际上最小化了可读性方面的差异。 然而,与选项1不同,选项3仅定义a_list一次 - 在定义do_something时。 这正是我们想要的。

备选方案3与备选方案2相比:

尽可能避免全局变量。 选项3允许您这样做。 此外,使用选项2,随着时间的推移或者如果其他人维护此代码, a_list的定义可能会与def do_something分开。 这可能不是什么大问题,但我认为这有点不可取。

如果您的a_list没有更改,请将其移出该功能。

  1. 你有一些数据
  2. 你有一个与之相关的方法
  3. 除非必须,否则您不希望为了优化方法的速度而全局保留数据。

我认为这就是课程的用途。

class Processor:
    def __init__(this):
        this.data = "any thing whatever".split()
    def fun(this,arg):
        # do stuff with arg and list

inst = Processor()
inst.fun("skippy)

此外,如果您有一天想要将数据分离到文件中,您只需修改构造函数即可。

好吧,它似乎归结为在函数中初始化数组:

import time
def fun1():
        a = ['any', 'think', 'whatever']
        sum = 0
        for i in range(100):
                sum += i

def fun2():
        sum = 0
        for i in range(100):
                sum += i


def test_fun(fun, times):
        start = time.time()
        for i in range(times):
                fun()
        end=time.time()
        print "Function took %s" % (end-start)

# Test
print 'warming up'
test_fun(fun1, 100)
test_fun(fun2, 100)

print 'Testing fun1'
test_fun(fun1, 100000)
print 'Testing fun2'
test_fun(fun2, 100000)

print 'Again'
print 'Testing fun1'
test_fun(fun1, 100000)
print 'Testing fun2'
test_fun(fun2, 100000)

结果:

>python test.py
warming up
Function took 0.000604152679443
Function took 0.000600814819336
Testing fun1
Function took 0.597407817841
Testing fun2
Function took 0.580779075623
Again
Testing fun1
Function took 0.595198154449
Testing fun2
Function took 0.580571889877

看起来没什么区别。

如果从未修改过列表,为什么要使用列表呢?

在不知道你的实际需求的情况下,我建议简单地使用一些if语句来完全删除列表和“从列表中读取内容”部分。

我一直在研究每天处理100,000,000条记录的自动化系统,其中1%的性能提升是巨大的。

我在该系统上学到了一个重要的教训:更快更好,但只有当你知道什么时候它足够快。

1%的改进可能会大大缩短总处理时间,但是当我们需要下一次硬件升级时,这还不够。 我的应用程序是如此之快,以至于我花费在最后1%的牛奶上花费的时间可能比新服务器的成本高。

在你的情况下,你必须在do_something上调用数万次才能在性能上有显着差异。 在某些情况下,这会产生影响,而在另一些情况下则不然。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM