我可以在Python列表理解中别名表达式以防止多次计算它们吗?

我可以在Python列表理解中别名表达式以防止多次计算它们吗?,python,alias,list-comprehension,Python,Alias,List Comprehension,我发现自己经常想写Python列表理解,如下所示: nearbyPoints = [(n, delta(n,x)) for n in allPoints if delta(n,x)<=radius] nearbyPoints=[(n,delta(n,x))对于所有点中的n,如果delta(n,x)关于#1,是的,它们将被评估多次 关于#2,方法是在单独的理解中计算和过滤: 精简版: [(x,fx,gx) for (x,fx,gx) in ((x,fx,g(fx)) for (x,fx)

我发现自己经常想写Python列表理解,如下所示:

nearbyPoints = [(n, delta(n,x)) for n in allPoints if delta(n,x)<=radius]
nearbyPoints=[(n,delta(n,x))对于所有点中的n,如果delta(n,x)关于#1,是的,它们将被评估多次

关于#2,方法是在单独的理解中计算和过滤:

精简版:

[(x,fx,gx) for (x,fx,gx) in ((x,fx,g(fx)) for (x,fx) in ((x,f(x)) for x in bigList) if fx < p) if gx<q]
a
b
使用生成器表达式,这样它们就不必实际实例化列表,只需在必要时进行计算

  • 如果在表达式中调用函数两次(包括在列表理解中),它实际上会被调用两次。Python无法知道您的函数是纯函数还是过程函数。在本例中,当您告诉它两次时,它会调用它

  • 在列表理解中,无法将赋值给变量,因为在Python中,赋值是语句,而不是表达式


  • 听起来你应该使用完整的循环,而不是列表理解。

    随着列表理解变得越来越复杂,它们也开始变得很难阅读。在这种情况下,最好将它们的内部结构转换为生成器函数,并给它们一个(希望)有意义的名称

    # First example
    def getNearbyPoints(x, radius, points):
        """Yields points where 'delta(x, point) <= radius'"""
        for p in points:
            distance = delta(p, x)
            if distance <= radius:
                yield p, distance
    
    nearbyPoints = list(getNearbyPoints(x, radius, allPoints))
    
    
    # Second example
    def xfg(data, p, q):
        """Yield 3-tuples of x, f(x), g(f(x))"""
        for x in data:
            f = f(x)
            if f < p:
                g = g(f)
                if g < q:
                    yield x, f, g
    
    newList = list(xfg(bigList, p, q))
    
    #第一个示例
    def getNearbyPoints(x,半径,点):
    
    “”“产生点,'delta(x,point)我有一个
    hack
    在列表/目录理解中创建别名。你可以在[alias\u value]
    技巧中对别名使用
    。例如,你有一个昂贵的函数:

    def_函数(x):
    打印(“称为非常昂贵的函数,即$2”)
    返回x*x+x
    
    还有一些数据:

    data=[4,7,3,7,2,3,4,7,3,1,1]
    
    然后,您希望对每个元素应用昂贵的函数,并基于它进行过滤。您要做的是:

    结果=[
    (十、价格昂贵)
    对于数据中的x
    对于[昂贵的_函数(x)]#别名中的昂贵
    如果价格>3
    ]
    打印(结果)
    
    第二个for将只迭代大小为1的列表,有效地使其成为别名。输出将显示昂贵的函数被调用12次,每个数据元素正好调用一次。然而,函数的结果被使用(最多)两次,一次用于过滤器,一次可能用于输出

    请始终确保像我一样使用多行布局这样的理解,并在别名所在的行中附加#alias。如果使用别名,理解会非常复杂,您应该帮助代码的未来读者了解您正在做的事情。这不是perl,您知道;)

    为了完整性,输出:

    调用了非常昂贵的函数,将花费2美元
    称为非常昂贵的函数,将是2美元
    称为非常昂贵的函数,将是2美元
    称为非常昂贵的函数,将是2美元
    称为非常昂贵的函数,将是2美元
    称为非常昂贵的函数,将是2美元
    称为非常昂贵的函数,将是2美元
    称为非常昂贵的函数,将是2美元
    称为非常昂贵的函数,将是2美元
    称为非常昂贵的函数,将是2美元
    称为非常昂贵的函数,将是2美元
    称为非常昂贵的函数,将是2美元
    [(4, 20), (7, 56), (3, 12), (7, 56), (2, 6), (3, 12), (4, 20), (7, 56), (3, 12)]
    

    代码:

    我不想在理解中写一个语句,如果有一点语法上的糖分就好了,这样可以避免再次输入。可能类似于“a:=f(x)"可能更好。但正如您所指出的,由于函数是第二次求值的,所以这并没有多大帮助。+1尽管我对元组索引有疑虑。此外,在某些情况下,函数或生成器函数是最佳选择。此代码的可读性似乎远不如@ncoghlan的解决方案或我的解决方案。@Amber,这不是吗如果f(x)
    ,则为(x,f(x))in((x,f(x))中的(x,f(x))在bigList中的(x)进行冗余。
    [(x,fx,gx) for (x,fx,gx) in ((x,fx,g(fx)) for (x,fx) in ((x,f(x)) for x in bigList) if fx < p) if gx<q]
    
    [(x,f,g) for (x,f,g) in
      ((x,f,g(f)) for (x,f) in
         ((x,f(x)) for x in bigList)
      if f < p)
    if g<q]
    
    a = ( (x,f(x)) for x in bigList )
    b = ( (x,fx,g(fx)) for (x,fx) in a if fx<p )
    results = [ c for c in b if c[2] < q ] # faster than writing out full tuples
    
    # First example
    def getNearbyPoints(x, radius, points):
        """Yields points where 'delta(x, point) <= radius'"""
        for p in points:
            distance = delta(p, x)
            if distance <= radius:
                yield p, distance
    
    nearbyPoints = list(getNearbyPoints(x, radius, allPoints))
    
    
    # Second example
    def xfg(data, p, q):
        """Yield 3-tuples of x, f(x), g(f(x))"""
        for x in data:
            f = f(x)
            if f < p:
                g = g(f)
                if g < q:
                    yield x, f, g
    
    newList = list(xfg(bigList, p, q))