“更好”;如果不是“无”,则返回“;用Python

“更好”;如果不是“无”,则返回“;用Python,python,syntax,Python,Syntax,有没有更好的方法用python编写此代码 result = slow_function() if result: return result [...] 函数slow\u函数可以返回一个值或None并且速度很慢,因此这是不可行的: if slow_function(): return slow_function() 第一种方法没有什么错,但是对于python来说,使用临时变量似乎有些过分 当您使用对f的递归调用以及局部假设来解决问题时,此代码非常有用,例如,您从列表中选择一个

有没有更好的方法用python编写此代码

result = slow_function()
if result:
    return result
[...]
函数
slow\u函数
可以返回一个值或
None
并且速度很慢,因此这是不可行的:

if slow_function():
    return slow_function()
第一种方法没有什么错,但是对于python来说,使用临时变量似乎有些过分

当您使用对
f
的递归调用以及局部假设来解决问题时,此代码非常有用,例如,您从列表中选择一个项目,然后检查是否存在可行的解决方案,否则您必须选择另一个。比如:

def f(n):
    for x in xrange(n):
        result = slow_function(x):
        if result:
            return result
        [...]
用更地道的语言,比如:

def f(n):
    for x in xrange(n):
        return slow_function(x) if is not None
这可以扩展到检查任何类型的值。这将是一个易于阅读的返回if语句


代码爱好者的附加示例 假设您有一个数字列表:

lists = [[1,2,3],[4,5],[6,7,8],[9,10],...]
您希望为每个列表选择一个项目,以便选择中最多有一个偶数。可能有很多列表,所以尝试每种组合都是浪费,因为你已经知道如果你开始选择[1,2,4,…],可能没有可行的解决方案

def check(selected):
    even_numbers = filter(lambda n: (n % 2) == 0, selected)
    return len(even_numbers) < 2

def f(lists, selected=[]):
    if not lists:
        return selected

    for n in lists[0]:
        if check(selected + [n]):
            result = f(lists[1:], selected + [n])
            if result:
                return result
到目前为止,我所做的最好的工作就是将函数转换为可行解决方案的生成器:

def f(lists, selected=[]):
    if not lists:
        yield selected
    else:
        for n in lists[0]:
            if check(selected + [n]):
                for solution in f(lists[1:], selected + [n]):
                    yield solution

在不知道您还想返回什么的情况下,有几种选择

  • 您可以只返回函数的结果,
    None
    或not:

    return slow_function()
    
    在这种情况下,您依赖于调用者知道如何处理
    None
    值,并且真正地只是将逻辑转移到哪里

  • 如果要返回的是默认值而不是无值,则可以执行以下操作:

    return slow_function() or default
    
    在上面的例子中,如果
    slow\u函数
    None
    (即“falsy”),它将返回后一个值,否则,如果
    slow\u函数
    返回一个“truthy”值,它将返回该值。注意,如果
    slow\u函数
    可以返回其他“falsy”值,如
    False
    []
    或0,这些值将被忽略

  • 或者,有时您拥有的是完全有效的代码。您希望与值进行比较,如果它是值,则返回它。您拥有的代码在其功能上是显而易见的,有时这比代码的“聪明”更重要

  • 根据注释,如果您的代码在值为
    None
    时必须继续运行,那么最明显的方法就是将其存储为临时值。但是,这不是一件坏事,因为它读起来很清楚

    • 计算一个值并将其存储为结果
    • 如果有有效的结果,请返回它
    • 否则,继续做一些事情以获得更好的结果

    Better通常是非常主观的,我看不到任何明显的方法可以从计算的角度来改进它,正如我所写的,它是非常人性化的,这是一个明显的优势。其他解决方案可能更短或更聪明,但人类可读性往往是代码的一大优势。

    本质上,您希望对表达式求值,然后在不将其绑定到局部变量的情况下使用它两次。由于我们没有匿名变量,唯一的方法就是将其传递到函数中。幸运的是,当前函数是否返回的控制流不受其调用的函数控制。。。但是,异常会向上传播调用堆栈

    我不会说这更好,但您可以滥用异常来获得您想要的。这永远不应该被真正使用,它更多的是一种好奇心的锻炼。结果会是这样的(注意装饰器的使用):

    输出为:

    Checking 2...
    Checking 3...
    Checking 4...
    Checking 5...
    1000
    
    诀窍是借助异常处理,因为这些异常会在函数调用之间传播。如果您喜欢,以下是实现:

    class ReturnExc(Exception):
        def __init__(self, val):
            self.val = val
    
    def return_if(val):
        if val is not None:
            raise ReturnExc(val)
    
    def if_returner(f):
        def wrapped(*args, **kwargs):
            try:
                return f(*args, **kwargs)
            except ReturnExc, e:
                return e.val
        return wrapped
    

    您所写的看起来不错,但如果您想避免使用多个返回语句,可以执行以下操作:

    def f():
        result = slow_function()
        if result is None:
            [...]
            result = [...]
        return result
    
    def solve(args, result_so_far):
        if not slow_check_is_feasible(result_so_far):
            #dead-end
            return None
    
        if not args:
            #valid and done
            return result_so_far
    
        for i, item in enumerate(args):
            #pass list without args - slow
            new_args = args[:]
            del new_args[i]
            result = solve(new_args, accumulate_result(result_so_far, item)
            if result is not None:
                #found it, we are done
                return result
            #otherwise keep going
    
    def solve_all(args, result_so_far):
        if not slow_check_is_feasible(result_so_far):
            #dead-end
            return
    
        if not args:
            #yield since result was good
            yield result_so_far
            return
    
        for i, item in enumerate(args):
            #pass list without args - slow
            new_args = args[:]
            del new_args[i]
            for result in solve(new_args, accumulate_result(result_so_far, item):
                yield result
    

    对于
    slow_function
    在循环上运行的问题,生成器表达式似乎是一种可行的方法。在Python 3中,这里的所有内容都是惰性的,因此您可以免费获得过滤器:

    f = filter(slow_function(x) for x in range(...))
    
    在Python 2中,您只需要itertools:

    from itertools import ifilter
    
    f = ifilter(slow_function(x) for x in xrange(...))
    
    每次迭代只会在您请求时进行。如果您需要在函数返回false时继续操作,则需要将
    false
    ness作为哨兵,这样您的解决方案就可以了:

    def f():
      for x in xrange(...):
        sentinel = slow_function(x)
        if sentinel:
          return sentinel
        # continue processing
    
    或者您也可以在此处使用生成器保存一个变量:

    from itertools import imap
    
    def f():
      for x in imap(slow_function, xrange(...)):
        if x:
          return x
        # continue processing
    
    你可能会更清楚地知道你想做什么:

    假设您传递一个列表,它选择了一个项目,然后调用自己传递列表而不传递该项目,依此类推,直到您没有更多的项目。您检查解决方案是否可行,如果可行,您将返回解决方案,这需要一直通过调用堆栈,否则您将不返回任何解决方案。通过这种方式,您可以按拓扑顺序探索所有问题,但当您知道以前选择的项目无法创建可行的解决方案时,也可以跳过检查

    也许您可以尝试使用
    yield
    而不是
    return
    。也就是说,递归函数不会生成一个解决方案,但会生成所有可能的解决方案。如果没有一个具体的例子,我无法确定你到底在做什么,但在此之前我要说:

    def f():
        result = slow_function()
        if result is None:
            [...]
            result = [...]
        return result
    
    def solve(args, result_so_far):
        if not slow_check_is_feasible(result_so_far):
            #dead-end
            return None
    
        if not args:
            #valid and done
            return result_so_far
    
        for i, item in enumerate(args):
            #pass list without args - slow
            new_args = args[:]
            del new_args[i]
            result = solve(new_args, accumulate_result(result_so_far, item)
            if result is not None:
                #found it, we are done
                return result
            #otherwise keep going
    
    def solve_all(args, result_so_far):
        if not slow_check_is_feasible(result_so_far):
            #dead-end
            return
    
        if not args:
            #yield since result was good
            yield result_so_far
            return
    
        for i, item in enumerate(args):
            #pass list without args - slow
            new_args = args[:]
            del new_args[i]
            for result in solve(new_args, accumulate_result(result_so_far, item):
                yield result
    
    现在看起来是这样的:

    def f():
        result = slow_function()
        if result is None:
            [...]
            result = [...]
        return result
    
    def solve(args, result_so_far):
        if not slow_check_is_feasible(result_so_far):
            #dead-end
            return None
    
        if not args:
            #valid and done
            return result_so_far
    
        for i, item in enumerate(args):
            #pass list without args - slow
            new_args = args[:]
            del new_args[i]
            result = solve(new_args, accumulate_result(result_so_far, item)
            if result is not None:
                #found it, we are done
                return result
            #otherwise keep going
    
    def solve_all(args, result_so_far):
        if not slow_check_is_feasible(result_so_far):
            #dead-end
            return
    
        if not args:
            #yield since result was good
            yield result_so_far
            return
    
        for i, item in enumerate(args):
            #pass list without args - slow
            new_args = args[:]
            del new_args[i]
            for result in solve(new_args, accumulate_result(result_so_far, item):
                yield result
    
    好处是:

    • 您生成所有答案,而不仅仅是第一个答案,但是如果您仍然只需要一个答案,那么您就可以得到第一个结果
    • 在使用返回值进行错误检查和回答之前。现在你只有在得到答案时才会屈服

    这并不是一个真正的建议,但你可以滥用列表理解,按照以下思路做一些事情:

    # Note: Doesn't work in python 3.
    def func():
        if [value for value in (slow_function(),) if value is not None]:
            return value
        # continue processing...
    

    为什么这样做太过分了?另外,如果结果为
    None
    ,会发生什么情况,您会返回什么?函数中
    if
    之后是否有其他代码?是的,很抱歉,它不明确,有其他代码。例如,当您