社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

在Python中进行处理时,如何确保任意函数调用的列表不会经过短路点而被急切地求值?

Kent Shikama • 5 年前 • 1613 次点击  

例如,给定

def expensive_call(x):
    print(x)
    if x == "d":
        return x
def expensive_call_2(x, y):
    print(x)
    print(y)
    return x + y

a = [expensive_call("a"), expensive_call_2("b", "c"), expensive_call("d")]
next((e for e in a if e is not None), 'All are Nones')

输出是

a
b
c
d
Out[22]: 'bc'

自从 expensive_call("d") 被热切地评价,注意“d”被打印即使 next 第二次呼叫时呼叫短路,输出为“BC”。

我把名单上的电话都硬编码了 a 不必是列表数据结构。

一种可能的解决方案如下:

a = ['expensive_call("a")', 'expensive_call_2("b", "c")', 'expensive_call("d")']
def generator():
    for e in a:
        r = eval(e)
        if r is not None:
            yield r
next(generator(), 'All are Nones')

输出是

a
b
c
Out[23]: 'bc'

如所愿。但是,我不喜欢使用eval。我也不希望使用任何一个最初将函数指针和参数分开的解决方案 (expensive_call, ("a")) . 理想情况下我会有

a = lazy_magic([expensive_call("a"), expensive_call_2("b", "c"), expensive_call("d")])
next((e for e in a if e is not None), 'All are Nones')

请注意 https://stackoverflow.com/a/3405828/2750819 是一个类似的问题,但仅适用于函数具有相同方法签名的情况。

Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/48298
 
1613 次点击  
文章 [ 2 ]  |  最新文章 5 年前
rassar
Reply   •   1 楼
rassar    5 年前

您可以使用以下装饰器:

def lazy_fn(fn):
    return lambda *args: lambda: fn(*args)

(也可以表示为 lazy_fn = lambda fn: lambda *args: lambda: fn(*args) 如果你喜欢羊肉。)

像这样使用:

@lazy_fn
def expensive_call(x):
    print(x)
    if x == "d":
        return x

@lazy_fn
def expensive_call_2(x, y):
    print(x)
    print(y)
    return x + y

a = [expensive_call("a"), expensive_call_2("b", "c"), expensive_call("d")]
print(next((e for e in map(lambda i: i(), a) if e is not None), 'All are Nones'))

输出:

a
b
c
bc

注意不要使用 for e in a ,您需要使用 for e in map(lambda i: i(), a) 是的。

Peter Wood
Reply   •   2 楼
Peter Wood    5 年前

您可以将它们全部放入一个函数中,并生成结果:

def gen():
    yield expensive_call("a")
    yield expensive_call_2("b", "c")
    yield expensive_call("d")


result = next(
    (value for value in gen() if value is not None),
    'All are Nones')

另一个解决方案是 partial 应用程序:

from functools import partial

calls = [partial(expensive_call, 'a'),
         partial(expensive_call_2, 'b', 'c'),
         partial(expensive_call, 'd')]

然后评估:

next((result for call in calls
      for result in [call()]
      if result is not None),
     'All results None')