将lambda表达式作为可调用的传递给dbus.接口连接_信号



我有一个类"Listener",它将回调连接到D-Bus信号。回调和信号名称由另一个类"Client"提供。如果客户端提供的回调被传递到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"one_answers"DeviceChanged"都做出反应,但只调用最后添加的回调。如果我只连接一个信号,行为是预期的,但一旦我连接多个信号,将lambda表达式作为回调传递,两个信号都会触发对添加的最后一个回调的调用。

有人知道这里发生了什么吗?

基本问题是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

原因是您需要capturelambda表达式中的变量,否则它们的值将只是循环结束时的值。

最新更新