有没有更好的方法在python中编写这段代码?
result = slow_function()
if result:
return result
[...]
Run Code Online (Sandbox Code Playgroud)
该函数slow_function可以返回一个值,或者None它很慢,所以这是不可行的:
if slow_function():
return slow_function()
Run Code Online (Sandbox Code Playgroud)
第一种方式没有任何问题,但使用临时变量似乎对python来说太过分了.
当您解决在使用递归调用过的问题.此代码是非常有用的f,并与当地的假设,比如你从列表中选择一个项目,然后检查是否有一个可行的解决方案,否则,你必须选择另外一个.就像是:
def f(n):
for x in xrange(n):
result = slow_function(x):
if result:
return result
[...]
Run Code Online (Sandbox Code Playgroud)
不是更好的东西,如:
def f(n):
for x in xrange(n):
return slow_function(x) if is not None
Run Code Online (Sandbox Code Playgroud)
这可以扩展到检查任何类型的值.如果声明,它将是一个易于阅读的返回.
想象一下,你有一个数字列表列表:
lists = [[1,2,3],[4,5],[6,7,8],[9,10],...]
Run Code Online (Sandbox Code Playgroud)
并且您希望为每个列表选择一个项目,以便在选择中最多有一个偶数.可能有很多列表,所以尝试每个组合都会浪费,因为你已经可以告诉你,如果你开始选择[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
Run Code Online (Sandbox Code Playgroud)
这样的语法不会更好吗:
def f(lists, selected=[]):
return selected if not lists
for n in lists[0]:
if check(selected + [n]):
return f(lists[1:], selected + [n]) if is not None
Run Code Online (Sandbox Code Playgroud)
到目前为止,我所做的最好的事情是在可行解决方案的生成器中转换函数:
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
Run Code Online (Sandbox Code Playgroud)
小智 14
在不知道您可能想要返回的其他内容的情况下,有几个选项.
你可以只返回函数的结果None:
return slow_function()
Run Code Online (Sandbox Code Playgroud)
在这种情况下,您依赖于调用者知道如何处理该None值,并且实际上只是改变您的逻辑.
如果您有一个默认值而不是None,则可以执行以下操作:
return slow_function() or default
Run Code Online (Sandbox Code Playgroud)
在上面,如果slow_function是None(这是"假")它将返回后一个值,否则,如果slow_function返回"truthy"值,它将返回该值.当心,如果slow_function可以返回其他"falsy"的价值观,像False,[]或0,这些将被忽略.
或者,有时您所拥有的是完全有效的代码.您想要与值进行比较,如果是值,则返回它.你所拥有的代码在它的作用中是显而易见的,有时这比代码的"聪明"更重要.
按照意见,如果你的代码必须继续运行,如果该值None,则最明显的方式来做到这一点是它存储为一个临时的值.但是,这并不是一件坏事,因为它读得很干净.
更好的通常是非常主观的,我无法从计算的角度看到任何明显的方法来改进这一点,并且正如所写,它是非常人性化的,这是一个明显的优势.其他解决方案可能更短或更聪明,但人类可读性通常是代码的优势.
您的最新评论可能会让您更清楚自己想要做什么:
想象一下,你传递fa列表并选择一个项目,然后调用自己通过列表而没有项目,依此类推,直到你没有更多的项目.您检查解决方案是否可行,如果可行,您将返回解决方案,这需要一直通过调用堆栈,否则返回None.这样,你将探讨的拓扑次序所有的问题,但你也可以跳过检查时,您知道,以前选择的项目将不能创建一个可行的解决方案.
也许你可以尝试使用yield而不是return.也就是说,您的递归函数不会生成一个解决方案,但会产生所有可能的解决方案.如果没有一个具体的例子,我无法确定你在做什么,但在此之前说:
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
Run Code Online (Sandbox Code Playgroud)
现在它看起来像这样:
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
Run Code Online (Sandbox Code Playgroud)
好处是:
基本上你想要评估一个表达式,然后使用它两次而不将它绑定到局部变量.由于我们没有匿名变量,唯一的方法是将它传递给函数.幸运的是,当前函数返回的控制流程不受它调用的函数的控制......但是,异常会传播到调用堆栈中.
我不会说这更好,但你可以滥用例外来获得你想要的东西.这应该永远不会被使用,而且更多是好奇心的练习.结果最终看起来像这样(注意装饰器的使用):
def slow_function(x):
if x % 5 == 0:
return x * 200
@if_returner
def foobme(l):
for i in l:
print "Checking %s..." % (i,)
return_if(slow_function(i))
print foobme([2, 3, 4, 5, 6])
Run Code Online (Sandbox Code Playgroud)
输出是:
Checking 2...
Checking 3...
Checking 4...
Checking 5...
1000
Run Code Online (Sandbox Code Playgroud)
诀窍是捎带异常处理,因为那些跨函数调用传播.如果你喜欢它,这是实现:
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
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
21136 次 |
| 最近记录: |