我如何将块传递给 Python 中的函数,就像在 Ruby 中传递块的方式一样

new*_*ike 6 python

在 Ruby 中,我可以将一段代码传递给一个方法。

例如,我可以将不同的代码块传递给get_schedules_with_retries方法。

并通过调用 black.call 调用块

我想知道如何在 Python 中实现该逻辑,

因为我有很多代码块,需要重试模式。

我不喜欢retry logic在许多代码块中复制粘贴

例子:

def get_schedules_with_retries(&block)
  max_retry_count = 3
  retry_count = 0
  while (retry_count < max_retry_count)
    begin
      schedules = get_more_raw_schedules
      block.call(schedules)
    rescue Exception => e
      print_error(e)
    end
    if schedules.count > 0
      break
    else
      retry_count+=1
    end
  end
  return schedules
end

get_schedules_with_retries do |schedules|
  # do something here
end

get_schedules_with_retries do |schedules|
  # do another thing here
end  
Run Code Online (Sandbox Code Playgroud)

Yan*_*ier 6

在 Python 中,块是一种语法特征(块开头语句(如 if 或 def)下的缩进)而不是对象。您期望的功能可能是闭包(可以访问块外部的变量),您可以使用内部函数来实现它,但可以使用任何可调用的功能。由于lambdaPython 中的工作方式,您所展示的内联函数定义do |arg|仅限于单个表达式。

这是用 Python 粗略重写的示例代码。

def get_schedules_with_retries(callable, max_retry_count = 3):
  retry_count = 0
  while retry_count < max_retry_count:
    schedules = get_more_raw_schedules()
    try:
      callable(schedules)
    except:  # Note: could filter types, bind name etc.
      traceback.print_exc()
    if schedules.count > 0:
      break
    else:
      retry_count+=1
  return schedules

get_schedules_with_retries(lambda schedules: single_expression)

def more_complex_function(schedules):
  pass # do another thing here
get_schedules_with_retries(more_complex_function)
Run Code Online (Sandbox Code Playgroud)

一种变体使用for循环来明确循环是有限的:

def call_with_retries(callable, args=(), tries=3):
  for attempt in range(tries):
    try:
      result=callable(*args)
      break
    except:
      traceback.print_exc()
      continue
  else:  # break never reached, so function always failed
    raise  # Reraises the exception we printed above
  return result
Run Code Online (Sandbox Code Playgroud)

通常,当传递这样的可调用对象时,您已经在某个地方拥有了您想要的函数,并且不需要重新定义它。例如,对象上的方法(绑定方法)是完全有效的可调用对象。