代码之家  ›  专栏  ›  技术社区  ›  twfx

Python在类中传递回调函数

  •  10
  • twfx  · 技术社区  · 10 年前

    我不得不尝试从非基于类的编码风格转变为基于类的代码风格,但面临着一个问题。optimize()函数采用回调函数mycallback()。该代码在非基于类的方法中工作得很好,但当我将它移到基于类的方式时,我收到了一个错误“mycallback()正好接受3个参数(1个给定)”。

    在基于类的方法中传递回调函数的正确方法是什么?

    (A) 非基于类的方法:

    def mycallback(model, where):
        pass
    
    model = Model()
    model.optimize(mycallback)
    

    (B) 基于类的方法:

    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
    

    虽然这是一个关于将回调函数传递给Gurobi(一个优化求解器内置函数)的问题,但我认为,如何将类中定义的回调函数传递到Python中的另一个函数是一个更一般的问题。


    方法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
    

    看起来很可能是Gurobi API问题。不知道是否有Gurobi开发人员会做出回应。

    5 回复  |  直到 10 年前
        1
  •  5
  •   jfs    10 年前

    一般来说 self.model.optimize(self.mycallback) 应该工作(注意:后面没有括号 mycallback ).

    如果代码序列化可调用对象,例如通过管道/套接字发送到另一个进程(甚至在不同的机器上),则可能会失败:

    from multiprocessing import Pool
    
    class C:
        def method(self, i):
            return "called", i
    
    if __name__=="__main__":
        print(Pool().map(C().method, range(10)))
    

    它适用于可选择方法的最新Python版本。

    或者,如果 model.optimize() 有一个错误,请检查确切的函数类型,而不是接受任何可调用的。

        2
  •  2
  •   rasul    3 年前

    这个问题在古罗比仍然存在 9.1 。我发现的一个简单的解决方法是将回调放在类中的方法中,例如:

    def solve(self):
        self.model.update()
           def lazyCallback(model, where):
           ...
        self.model.optimize(lazyCallback)
    
        3
  •  0
  •   brugaltheelder    10 年前

    似乎如果您从对象中删除回调,那么它就会起作用。您可以将其用作变通方法,直到您可以在类中获得回调。也就是说,从班级内部调用这条线。。。

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

    …设置为类外的此函数。

    def mycallback(self, model, where):     
        pass
    

    一点都不优雅,但希望有一位开发人员加入进来。

        4
  •  0
  •   Silke Horn    3 年前

    问题在于 self.mycallback 它是一个 方法 而Gurobi的 optimize 方法确实需要 作用 .

    有多种方法 自我.回拨 一个函数。以下是一些示例:

    一种方法是 mycallback 静态方法:

    @staticmethod
    def mycallback(model, where): 
        pass
    

    另一种方法是将该方法包装为如下函数:

    self.model.optimize(lambda model, where: self.mycallback(model, where))    
    
        5
  •  0
  •   gdm    2 年前

    我的两美分解决方案:

    
    import queue as Queue
    class A:
        def start(self):
           Queue.listen(callback=received)
    
        @staticmethod
        def received(*args):
           print(args)
    

    队列在另一个模块/文件中定义。