2012-11-20 57 views
0

我有一个类'Listener',它将回调连接到D-Bus信号。回调和信号名称由另一个类“客户”提供。如果客户端提供的回调函数作为接收信号时使用的回调函数传递给connect_to_signal(在dbus.Interface上),则一切都如预期的那样工作,即当接收到连接的信号时,会调用Client类中的回调方法。但是,如果我想在拦截信号并评估负载之前继续调用客户端回调函数,我想我可以使用lambda表达式并将它传递给connect_to_signal方法,如下例所示:将lambda表达式传递给dbus.Interface.connect_to_signal

import dbus 
from dbus.mainloop.glib import DBusGMainLoop 
DBusGMainLoop(set_as_default=True) 
from gi.repository import GObject 


class Client(object): 

    def __init__(self): 
     bus = dbus.SystemBus() 
     obj = bus.get_object("org.freedesktop.UDisks", "/org/freedesktop/UDisks") 
     interface = dbus.Interface(obj, "org.freedesktop.UDisks") 
     listener = Listener() 
     signals_and_callbacks = {"DeviceAdded": self.device_added, 
      "DeviceChanged": self.device_changed} 
     listener.listen_to_signals(interface, signals_and_callbacks) 

    def device_added(self, payload): 
     print "in device_added ", payload 

    def device_changed(self, payload): 
     print "in device_changed ", payload 


class Listener(object): 

    def listen_to_signals(self, interface, signals_and_callbacks): 
     for signal, callback in signals_and_callbacks.items(): 
      cb = lambda x: self.signal_cb(x, callback) 
      interface.connect_to_signal(signal, cb) 

    def signal_cb(self, opath, subscriber_cb): 
     print subscriber_cb 
     subscriber_cb(opath) 


if __name__ == "__main__": 
    client = Client() 
    mainloop = GObject.MainLoop() 
    mainloop.run() 

但是这不能按预期工作。信号被连接,在这种情况下,代码对'DeviceAdded'和'DeviceChanged'作出反应,但只添加最后一次回调。如果我只连接一个信号的行为如预期的那样,但只要我连接多个信号,将lambda表达式作为回调传递,两个信号都将触发的呼叫,最后回调被添加。

有没有人有任何想法这里发生了什么?

回答

1

基本问题是Python的范围规则以及如何设置回调。
这个例子说明您的问题(和解决方案):

def test1(): 
    print("test1") 

def test2(): 
    print("test2") 

def caller(name, fn): 
    print("calling function with name: {}".format(name)) 
    fn() 

class Driver(object): 
    def __init__(self): 

     self.signals = [] 

    def connect_to_signal(self, name, what_to_call): 
     self.signals.append((name, what_to_call)) 

    def run(self): 
     for name, signal in self.signals: 
      signal(1) 



def main(): 
    signals = {'test1':test1, 'test2':test2} 

    d = Driver() 

    for signal, callback in signals.items(): 
     cb = lambda x: caller(signal, callback) 
     #cb = lambda x,s=signal,c=callback: caller(s, c) # TRY THIS INSTEAD! 
     d.connect_to_signal(signal, cb) 

    d.run() 

if __name__ == '__main__': 
    main() 

如果运行这个功能,就是,你得到如下:

calling function with name: test2 
test2 
calling function with name: test2 
test2 

如果您注释掉行开始CB =拉姆达X,并取消以下行,现在你得到想要的:

calling function with name: test1 
test1 
calling function with name: test2 
test2 

的原因是,你需要在capture变量您lambda表达式,或者它们的值将只是它们在循环结束时的值。

+0

谢谢!在这里,我第n次指责python-dbus lib,结果证明这又是我的错......谁会想到? = d – JoGr

相关问题