将lambda表达式作为callable传递给dbus.Interface.connect_to_signal

时间:2012-11-20 14:14:34

标签: python lambda signals dbus

我有一个类'Listener',它将回调连接到D-Bus信号。回调和信号名称由另一个类“客户端”提供。如果客户端提供的回调被传递给connect_to_signal(在dbus.Interface上)作为接收信号时使用的回调,则一切都按预期工作,即在收到连接信号时调用类Client中的回调方法。

但是,如果我想在继续调用Clients回调之前“拦截”信号并评估有效负载,我想我可以使用lambda表达式并将其传递给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表达式作为回调传递,两个信号就会触发对 last 回调补充。

有谁知道这里发生了什么?

1 个答案:

答案 0 :(得分: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 = lambda x开始的行,并取消注释以下行,您现在可以得到所需的行:

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

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