“更好”;如果不是“无”,则返回“;用Python
有没有更好的方法用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的递归调用以及局部假设来解决问题时,此代码非常有用,例如,您从列表中选择一个
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
之后是否有其他代码?是的,很抱歉,它不明确,有其他代码。例如,当您