Pythonic vs Unpythonic

sPa*_*Paz 4 python runtime

考虑这两个执行以下操作的函数:给定一个单词,它会生成一个列表,其中单词中的每个位置都被字母表中的每个字符替换

alphabet = 'abcdefghijklmnopqrstuvwxyz'
Run Code Online (Sandbox Code Playgroud)

版本1(Pythonic):

def replace1_word( word ):
    return [word[:w]+alphabet[i]+word[w+1:] 
            for w in range(len(word)) 
            for i in range(len(alphabet))]
Run Code Online (Sandbox Code Playgroud)

版本2(Unpythonic):

def replace1_word2( word ):
    res=[]
    for w in range(len(word)):
        for i in range(len(alphabet)):
            res.append( word[:w] + alphabet[i] + word[w+1:] )
    return res
Run Code Online (Sandbox Code Playgroud)

我使用timeit模块运行1000次并测量时间,平均运行时间差异在0.028毫秒到0.040毫秒之间.

我的问题是在第二个版本中代码的哪个部分/行是昂贵的,为什么?它们"似乎"以相同的方式工作,并以列表格式返回相同的结果.

Abh*_*jit 6

我的问题是在第二个版本中代码的哪个部分/行是昂贵的,为什么?它们"似乎"以相同的方式工作,并以列表格式返回相同的结果.

不,他们不是.如果有疑问,请始终对其进行分析,它将为您提供每个操作的成本图.只是看下面的O/P现在告诉你,你的第二个功能有什么代价?

>>> cProfile.run("replace1_word2('foo bar baz')")
         313 function calls in 0.000 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    0.000    0.000 <pyshell#216>:1(replace1_word2)
        1    0.000    0.000    0.000    0.000 <string>:1(<module>)
       12    0.000    0.000    0.000    0.000 {len}
      286    0.000    0.000    0.000    0.000 {method 'append' of 'list' objects}
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
       12    0.000    0.000    0.000    0.000 {range}


>>> cProfile.run("replace1_word('foo bar baz')")
         27 function calls in 0.000 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    0.000    0.000 <pyshell#220>:1(replace1_word)
        1    0.000    0.000    0.000    0.000 <string>:1(<module>)
       12    0.000    0.000    0.000    0.000 {len}
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
       12    0.000    0.000    0.000    0.000 {range}
Run Code Online (Sandbox Code Playgroud)

注意解释什么替换追加(或版本1如何生成列表)

在Python中,函数调用会产生额外的开销.在前一种情况下,list.append多次调用,在列表理解的情况下,列表生成为单个表达式.所以从某种意义上说,对于具有循环结构的列表理解没有等效的符号.List comprehension是Python中的一个强大工具,而不是循环的装饰语法.

结语

如果你让我写一个函数来解决这个问题,我会最终得到一些东西

>>> from itertools import product
>>> from string import ascii_lowercase
>>> def replace1_word4(word):
         words = ('{}'.join([word[:w], word[w+1:]]) for w in range(len(word)))
         return [word.format(replace)
                 for  word, replace in product(words, ascii_lowercase)]
Run Code Online (Sandbox Code Playgroud)