我可以在Python列表理解中对表达式进行别名以防止它们被多次求值吗?

2024-10-02 10:32:26 发布

您现在位置:Python中文网/ 问答频道 /正文

我发现自己经常想写这样的Python列表理解:

nearbyPoints = [(n, delta(n,x)) for n in allPoints if delta(n,x)<=radius]

希望这能为我为什么要这么做提供一些背景,但是 也是需要根据计算/比较多个值的情况 要素:

^{pr2}$

所以我有两个问题:

  1. 所有这些函数将被多次求值还是结果被缓存? 语言是指定的还是特定于实现的?我现在用的是2.6,但是3.x会不同吗?在
  2. 有没有更简洁的写作方法?有时f和g是长表达式 复制很容易出错,看起来很混乱。我真的很想 写下这个:
newList = [(x,a=f(x),b=g(a)) for x in bigList if a<p and b<q]

但那不管用。有没有理由不支持这种语法?可以 它是通过this这样的方式完成的? 还是只能使用多个listcomps或for循环?在


Tags: 函数in语言列表forif情况delta
3条回答

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

# 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))

我有一个hack在list/dict理解中创建别名。您可以使用for alias_name in [alias_value]技巧。例如,您有一个昂贵的函数:

def expensive_function(x):
    print("called the very expensive function, that will be $2")
    return x*x + x

还有一些数据:

^{pr2}$

然后你要对每个元素应用昂贵的函数,并基于它进行过滤。你要做的是:

result = [
    (x, expensive)
    for x in data
    for expensive in [expensive_function(x)] #alias
    if expensive > 3
]

print(result)

第二个for将只迭代大小为1的列表,使其成为别名。输出将显示这个昂贵的函数被调用了12次,每个数据元素只调用一次。然而,函数的结果被使用(最多)两次,一次用于滤波器,一次用于输出。在

请始终确保像我一样使用多行来布局这样的理解,并将#alias附加到别名所在的行。如果您使用别名,理解get相当复杂,您应该帮助未来的代码读者了解您正在做什么。这不是perl,你知道;)。在

为了完整性,输出:

called the very expensive function, that will be $2
called the very expensive function, that will be $2
called the very expensive function, that will be $2
called the very expensive function, that will be $2
called the very expensive function, that will be $2
called the very expensive function, that will be $2
called the very expensive function, that will be $2
called the very expensive function, that will be $2
called the very expensive function, that will be $2
called the very expensive function, that will be $2
called the very expensive function, that will be $2
called the very expensive function, that will be $2
[(4, 20), (7, 56), (3, 12), (7, 56), (2, 6), (3, 12), (4, 20), (7, 56), (3, 12)]

代码:http://ideone.com/7mUQUt

关于#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]

扩展的较长版本使其更易于遵循:

^{pr2}$

这将尽可能少地调用fg(每个f(x)的值不是< p将永远不会调用{},并且对于bigList中的每个值,f只调用一次)。在

如果您愿意,也可以使用中间变量获得更简洁的代码:

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

ab使用生成器表达式,这样它们就不必实际实例化列表,并在必要时进行简单的求值。在

相关问题 更多 >

    热门问题