Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How could I pass block to a function in Python which is like the way to pass block in Ruby

Tags:

python

In Ruby, I can pass a block of code to a method.

For example, I can pass different code blocks to get_schedules_with_retries method.

And invoke the block by calling black.call

I'd like to know how could I implement that logic in Python,

Because I have lots of code blocks, need retry pattern.

I don't like copy paste the retry logic in many code blocks

Example:

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  
like image 379
newBike Avatar asked Feb 15 '16 09:02

newBike


People also ask

How do you pass an object as a function argument in Python?

In MyClass there is one method my_method which takes one more argument apart from self. In class Person, MyClass is also used so that is imported. In method display() object of MyClass is created. Then the my_method() method of class MyClass is called and object of Person class is passed as parameter.

How do you pass a method in Python?

If you want to pass a method of a class as an argument but don't yet have the object on which you are going to call it, you can simply pass the object once you have it as the first argument (i.e. the "self" argument). Show activity on this post. Outputs: Running parameter f().


1 Answers

In Python, a block is a syntactic feature (an indentation under block opening statements like if or def) and not an object. The feature you expect may be a closure (which can access variables outside of the block), which you can achieve using inner functions, but any callable could be used. Because of how lambda works in Python, the inline function definition you've shown with do |arg| is limited to a single expression.

Here's a rough rewrite of your sample code in 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)

One variant uses a for loop to make it clear the loop is finite:

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

Frequently when passing callables like this, you'll already have the function you want available somewhere and won't need to redefine it. For instance, methods on objects (bound methods) are perfectly valid callables.

like image 77
Yann Vernier Avatar answered Sep 21 '22 19:09

Yann Vernier