【问题标题】:Can number of call from cProfile be trusted可以信任来自 cProfile 的调用次数吗
【发布时间】:2022-07-22 17:20:10
【问题描述】:

我一直在尝试将一些 for 循环列表创建转换为列表推导。我发现许多教程对于简单的案例都可以,但对于更复杂的案例(我正在考虑有多个 for 和/或多个 if 的案例)我如何判断理解是否与循环?有没有类似于 C 标准的 Python 标准?

一个简化的例子:str(a) 是一个函数,它接受一个字符串和 返回一个字符串。 strlist2 是等长字符串的列表

       strlist2=[]
       for x in strlist1:
           y=[str(x) for z in range(0,len(x)+1)]
           strlist2+=y

(注意 y 是一个列表,因此 += 而不是 .append)

我的第一次(错误)尝试是

       i.  strlist2=[y for x in strlst1
               for z in range(0,len(x)+1) for y in str()]

我后来想到了我认为正确的答案

      ii.   strlst2=[str(x) for x in strlst1 for z in range(0,len(x)+1)]

           

问题是,我的意思是什么。我假设

          strlin2=[]
          for x in strlist1:
             for z in range (0.len(x)+1):
                   temp=str(x)
                   for y in temp:
                        strlist2.append(y) 

但这意味着 len(strlint1)(len(strlist1[0])+1) 调用 str 这不是 cProfile 告诉我的。

【问题讨论】:

    标签: python


    【解决方案1】:

    我相信 Python 两种形式(大致[1])是等效的:

    # a convoluted way to generate the strings for the integers from 0 to 99
    for x in range(10):
      for y in range(10):
        str(x*10+y)
    

    [str(x*10+y) for x in range(10) for y in range(10)]
    

    根据我的经验,确实如此。但我从来没有检查过。让我们去做吧:

    >>> # The calls to `str` were not recorded for a strange reason,
    >>> # so instead I create a dummy function that I will supply to the profiled code
    >>> def foo(val): pass
    
    >>> # I bump the value to 10000 so that it takes a few seconds to run,
    >>> # so there is something to profile
    >>> cProfile.runctx("for x in range(10000):\n\tfor y in range(10000):\n\t\tfoo(x*10000+y)",
                        globals={"foo": foo}, locals={})
    
             100000003 function calls in 17.188 seconds
       Ordered by: standard name
       ncalls  tottime  percall  cumtime  percall filename:lineno(function)
    100000000    3.668    0.000    3.668    0.000 <input>:1(foo)
            1   13.520   13.520   17.188   17.188 <string>:1(<module>)
            1    0.000    0.000   17.188   17.188 {built-in method builtins.exec}
            1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
    
    >>> cProfile.runctx("[foo(x*10000+y) for x in range(10000) for y in range(10000)]",
                        globals={"foo": foo}, locals={})
    
             100000004 function calls in 14.998 seconds
       Ordered by: standard name
       ncalls  tottime  percall  cumtime  percall filename:lineno(function)
    100000000    3.530    0.000    3.530    0.000 <input>:1(foo)
            1   11.321   11.321   14.851   14.851 <string>:1(<listcomp>)
            1    0.147    0.147   14.998   14.998 <string>:1(<module>)
            1    0.000    0.000   14.998   14.998 {built-in method builtins.exec}
            1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
    

    fooncalls 都恰好是 100000000 (= 10000*10000)。

    它与specification for comprehension lists "displays" 匹配:

    理解由一个表达式组成,后跟至少一个 for 子句和零个或多个 for or if 子句。在这种情况下,新容器的元素是通过将每个 forif 子句视为一个块,从左到右嵌套,并在每次最里面时计算表达式以生成一个元素来生成的元素已到达区块。

    换句话说:理解的效果是一样的[1] 就好像for 已经以相同的顺序嵌套,并且内部循环的每次迭代都添加了一个新值.但是正如你所看到的,它还是有点快。

    [1]:来自the same spec as before,“理解在单独的隐式嵌套范围内执行。这确保分配给目标列表的名称不会“泄漏”到封闭范围内”。换句话说,这意味着您无法在理解之外访问您的xy


    旁注:有很多 Python 初学者教程,但实际上它们很少实现复杂的行为。为此,您通常会寻找实际的“生产”代码(通常在 GitHub 或 PIP 上)。

    【讨论】:

      猜你喜欢
      • 2011-11-10
      • 1970-01-01
      • 2010-09-14
      • 2010-11-10
      • 2016-10-24
      • 1970-01-01
      • 2011-08-15
      • 2018-05-05
      • 1970-01-01
      相关资源
      最近更新 更多