12

I have to try to move from the non-class-based coding style into class-based coding style, but facing an issue. The optimize() function takes a callback function mycallback(). The code works perfectly fine in Non-class-based method, but when I moved it to class-based method, I got an error "mycallback() takes exactly 3 arguments (1 given)".

What is the right way to pass a callback function in the class-based method?

(A) Non-class-based method:

def mycallback(model, where):
    pass

model = Model()
model.optimize(mycallback)

(B) Class-based method:

class A:
    def __init__(self):
        self.model = Model()

    def solve(self):
        # Try method 1:
        self.model.optimize(self.mycallback())      <--- Error: mycallback() takes exactly 3 arguments (1 given)
        # Try method 2:
        # self.model.optimize(self.mycallback)  <--- Error:  Callback argument must be a function

    def mycallback(self, model, where):     
        pass

While this is a problem regarding passing a callback function to Gurobi's (an optimization solver) built-in function, I believe it is a more general question on how to pass a callback function defined in a class to another function in Python.


Error For method 2:

   self.model.optimize(self.mycallback)  
   File "model.pxi", line 458, in gurobipy.Model.optimize      (../../src/python/gurobipy.c:34263)
   gurobipy.GurobiError: Callback argument must be a function

Looks like it is likely to be Gurobi API issue. Wonder if any Gurobi dev will response.

3
  • Why even have three parameters when all you do is pass Commented Mar 29, 2014 at 12:36
  • 5
    You don't need to call self.mycallback(), pass it as self.model.optimize(self.mycallback). Commented Mar 29, 2014 at 12:37
  • Please post the full traceback error message you see when using method 2. Commented Mar 29, 2014 at 13:00

5 Answers 5

6

In general, self.model.optimize(self.mycallback) should work (note: no parens after mycallback).

It may fail if the code serializes the callable e.g., to be send via pipe/socket to another process (even on different machine):

from multiprocessing import Pool

class C:
    def method(self, i):
        return "called", i

if __name__=="__main__":
    print(Pool().map(C().method, range(10)))

It works on recent Python versions where methods are pickable.

Or it may fail if model.optimize() has a bug and check for the exact function type instead of accepting any callable.

Sign up to request clarification or add additional context in comments.

Comments

2

This issue still persists in gurobi 9.1. A simple workaround I found is to put the callback inside a method in your class, for instance:

def solve(self):
    self.model.update()
       def lazyCallback(model, where):
       ...
    self.model.optimize(lazyCallback)

Comments

0

It seems that if you remove the callback from the object, then it works. You can use this as a work-around until you can get a callback working in-class. That is, call this line from within the class...

def solve(self):
    self.model.optimize(mycallback)

...to this function outside of the class.

def mycallback(self, model, where):     
    pass

Not elegant at all, but hopefully a developer chimes in.

Comments

0

The problem with self.mycallback is that it is a method while Gurobi's optimize method really expects a function.

There are multiple ways to make self.mycallback a function. Here are some examples:

One approach would be making mycallback a static method:

@staticmethod
def mycallback(model, where): 
    pass

Another would be wrapping the method into a function as follows:

self.model.optimize(lambda model, where: self.mycallback(model, where))    

Comments

0

My two cents solution:


import queue as Queue
class A:
    def start(self):
       Queue.listen(callback=received)

    @staticmethod
    def received(*args):
       print(args)

Queue is defined in another module/file.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.