Python 列表理解中的函数-是否经过多次评估

Python 列表理解中的函数-是否经过多次评估,python,list-comprehension,Python,List Comprehension,在python中,哪一种是更好的列表理解方法(在计算时间和cpu周期方面)。 在示例(1)中,值f(r)是在每次迭代中计算的,还是只计算一次并缓存 y=[x*f(r)表示xlist中的x] c=f(r) y=[x*c代表xlist中的x] 在哪里 我可能会选择后者,因为Python编译器不知道函数是否有副作用,所以会为每个元素调用它。函数f将为每个元素调用。它会为每个迭代求值。看看这个: >>> def f(): ... print("func") ... >&

在python中,哪一种是更好的列表理解方法(在计算时间和cpu周期方面)。 在示例(1)中,值f(r)是在每次迭代中计算的,还是只计算一次并缓存

  • y=[x*f(r)表示xlist中的x]

  • c=f(r)

    y=[x*c代表xlist中的x]

  • 在哪里


    我可能会选择后者,因为Python编译器不知道函数是否有副作用,所以会为每个元素调用它。

    函数
    f
    将为每个元素调用。

    它会为每个迭代求值。看看这个:

    >>> def f():
    ...     print("func")
    ... 
    >>> [f() for i in range(4)]
    func
    func
    func
    func
    [None, None, None, None]
    

    正如您所说,如果f()没有副作用,那么将返回值存储在变量上并使用该变量将是一个更快的解决方案。

    对于编译器/解释器来说,确定函数不需要多次调用是非常复杂的。然后很可能会多次调用该函数。因此,使用第二种解决方案始终是最好的解决方案。

    与名称查找相比,函数的执行时间非常短,如果函数被多次调用并且每次都需要相同的值,则缓存该值是可以接受的。

    Python可能可以自由地执行一次或多次,我不确定我是否会依赖任何观察到的行为。它可能在下一个版本中更改


    如果确保函数只调用一次对您很重要,请您自己调用并保存结果。

    以下是一个简单的方法:

    >>> def f():
    ...     print "called"
    ...     return 1
    ...
    >>> [1+f() for x in xrange(5)]
    called
    called
    called
    called
    called
    [2, 2, 2, 2, 2]
    

    因此,是的,如果函数每次都是相同的,那么最好在列表理解之外调用它一次。

    如何只调用一次?除非解释器能够保证
    f
    没有副作用,否则它必须在每次迭代中调用它no?@Davy8,当然有办法保证函数没有副作用。如果Python今天没有实现任何功能,那么它将来仍然可以自由地实现。如果函数使用
    eval()
    则无法确定任何内容。因此,每次通过循环对函数进行求值时,没有其他选择。是的,未来的版本可能会破坏语义,但是
    eval()
    的想法太基本了,不能破坏。@S.Lott:我不认为它做了这么复杂的事情。但从原则上讲,这是完全有可能的,所以这个问题并不像你想象的那么愚蠢。@s.Lott,当分析一个函数的副作用时,有三种可能的结果:是的,不是的,也说不出来。你似乎认为第三个的存在排除了其他两个,但事实并非如此。只要将“是/不能说”的情况集中在一起,优化将是安全的。使用某些JIT技术分析代码甚至可能是免费的。“选择是否取决于f(r)求值的复杂程度?”在这里如何定义“复杂”?更重要的是,Python何时以及如何确定“复杂性”。而且,更重要的是,当
    f(r)
    涉及
    eval()
    时,如何确定任何事情?抱歉,我的意思不清楚,我的意思是“我应该”,因为用户应该根据函数复杂度在(1)和(2)之间选择,还是我应该总是选择(2)。@ensnap:?“值f(r)是否计算一次并缓存?”在第二个示例中,是。在第一个示例中,no.和Python(假设存在
    eval()
    )无法为您进行优化。您在问什么?请更新问题以使其更清楚。@ensnap:“是否应按用户选择的“I”和“是否对函数进行多次计算”完全不同。请修改标题或问题以更好地匹配彼此。这非常令人困惑。@s.Lott标题问“函数是否在列表理解中被评估多次”。回答是肯定的。因此(2)是一个更好的方法。“可能”?考虑到函数可以使用
    eval()
    ,还有什么选择呢?我说可能是因为我没有写任何代码来证实我的理论。Python怎么可能“知道函数是否有副作用”?函数可以使用
    eval()
    exec
    做任何事情。因为
    eval()
    存在,函数必须每次求值,否则语义会严重受损。@S Lott为什么eval的存在会保证Python解释器无法确保没有副作用?没有apply函数或map函数。map正在创建生成器对象。我只是想为avo添加一种变通方法id python列表理解中的多个函数调用:将函数调用放在只计算一次的嵌套理解中。在您的示例中,我的意思是:
    [1+f_2;for f_2;in[f()]for x in xrange(5)]
    ——注意这里只调用一次
    f()
    >>> def f():
    ...     print "called"
    ...     return 1
    ...
    >>> [1+f() for x in xrange(5)]
    called
    called
    called
    called
    called
    [2, 2, 2, 2, 2]