【问题标题】:Function definition in Python takes a lot of timePython中的函数定义需要很多时间
【发布时间】:2014-06-02 23:02:12
【问题描述】:

为什么python在定义时要计算p的值?定义这个函数需要很长时间。

def f():
    raise Exception('Some error')
    p = 2322111239**42322222334923492304923

print 'Defined!'

另外,如果在定义时计算p的值,为什么可以无误地定义这个函数?

def f():
    return 4
    p = 11/0

这显然可以正常工作,因为不涉及常量:

def f():
    raise Exception('Some error')
    x=42322222334923492304923
    p = 2322111239**x

print 'Defined!'

【问题讨论】:

  • PS:尝试在你的IDLE中定义top函数。它会崩溃:)

标签: python function python-2.7


【解决方案1】:

它是窥视孔优化器:

https://github.com/python/cpython/blob/2.7/Python/peephole.c#L88

具体见104-106:

case BINARY_POWER:
    newconst = PyNumber_Power(v, w, Py_None);
    break;

目的是加快函数的运行时执行,在导入模块时以较慢的定义时间为代价。这个想法是您只需要为函数编译一次代码,但您可能需要多次调用它,并且两个常量的求幂 binop 的结果不会改变,因此不需要每次都重新计算。

注意:在 Python 3 中,constant folding 已移至 ast_opt.c 中的新 AST 优化器,peephole.c 已消失。代码现在有 safeguards 以防止过度急切的优化可能导致缓慢或占用大量内存的解析/编译步骤,如本问题所示。

【讨论】:

  • 因为这是记录 python(语言),而不是 cpython(实现)。
  • @anon 实际上并没有执行函数,它只是计算其中的常量的值。
  • 我并不是说 wim 是错的。 (我没有投反对票,实际上我投了赞成票),但是@dano:你可以对文档字符串争论同样的事情......我只是发现文档具有误导性。
  • @dawg 它确实在编译时抛出错误,但它是在 cpython 中处理的。该案例的错误处理从第 209 行开始hg.python.org/cpython/file/cd87afe18ff8/Python/peephole.c#l209
【解决方案2】:

解释器的此功能称为constant folding(有关一些不错的信息,请参阅here)。存在几个解决过于激进的常量折叠的问题。类似的问题也可能出现在内存中,大量内存被分配并再次被直接丢弃(参见here)。

【讨论】:

    【解决方案3】:

    让我们尝试一个更合理的数字:

    >>> def f():
    ...    p=123**45
    ... 
    

    如果你使用dis查看字节码,你可以看到p的值是在函数被调用之前定义的:

    >>> import dis
    >>> dis.dis(f)
      2           0 LOAD_CONST               3 (11110408185131956285910790587176451918559153212268021823629073199866111001242743283966127048043)
                  3 STORE_FAST               0 (p)
                  6 LOAD_CONST               0 (None)
                  9 RETURN_VALUE
    

    【讨论】:

    • @wim:这是一个答案。您的评论也是一个答案。
    • 是的,我就是这么想的,但是 Python 为什么要这么做呢?我的意思是他们有什么理由让 Python 做到这一点?
    • 大多数程序员没有定义永远不会被调用的函数的习惯。
    • 一旦你导入一个库,大多数函数都可能永远不会被调用。但是,您可以争辩说大多数程序不会 p = 2322111239**42322222334923492304923 ;)
    • 结果将存储在编译后的.pyc 文件中,因此导入仅在第一次使用时会花费很长时间。无论如何,如果真的有问题,您可以简单地将p 定义为等于该乘法的结果,而不是进行乘法运算!
    猜你喜欢
    • 1970-01-01
    • 2020-08-04
    • 1970-01-01
    • 1970-01-01
    • 2020-03-19
    • 2018-05-21
    • 1970-01-01
    • 1970-01-01
    • 2021-12-02
    相关资源
    最近更新 更多