首页 > 解决方案 > 如何管理 I/O 设备的多个唯一实例

问题描述

我有一个 I/O 串行设备(一个类,在这里调用它SerialPort),我的程序的其他部分将读取/写入。SerialPort处理与端口(pyserial)的连接,I/O 的线程化,并作为发布/订阅设计实现,如果有新消息,我程序中的其他类会被回调,或者可以编写新消息。该设备有超过 100 条支持的消息和响应,因此是 pub/sub 设计(不是这个问题的中心,只是想澄清选择)。

现在我需要添加 2 个(或更多)相同的设备。我想做的是让任何观察者调用类似的东西:

# The name of the devices and corresponding serial ports are known at run time. So in the program there will be N known devices.

# Where SerialPort("UniqueName1") is connected to port /dev/ttyUSB0
some_observer = Observer(SerialPort("UniqueName1"))
# Where SerialPort("UniqueName2") is connected to port /dev/ttyUSB2
other_observer = Observer(SerialPort("UniqueName2"))
# Here some_observer and random_observer both get the same instance of SerialPort("UniqueName1")
random_observer = Observer(SerialPort("UniqueName1"))

在 Observer() 中保存了 SerialPort 的实例(或接口),因此 Observer 可以编写并向 SerialPort 注册回调。我坚持的部分是如何处理对 SerialPort("UniqueName1") 的每次调用都应该返回已经连接的 SerialPort 对象(假设它之前已连接/初始化)。观察者应该只能说“我想与具有 UniqueName1(或 2)的设备交谈”

以这种方式,我可以通过在 Observer 中保留两个(或更多) SerialPort 引用来拥有两个 SerialPort 对象的观察者。我不需要这样做,但是如果我将来需要,这个设计不会限制我。

关于如何在 python (2.7) 中执行此操作的任何建议?我是 python 新手,边走边用谷歌搜索。我只需要帮助我应该将 python/伪代码放在下面的位置。我试图把它放在 Serialport 类中,但SerialPort.__init__(name)没有让我返回一个已经创建的 SerialPort 设备

# Somewhere in the code
sp = SerialPort(name="UniqueName1")
# Now in SerialPort, where all_serial_ports = list of available SerialPorts
for serial_ports in all_serial_ports:
    if serial_ports.name == name:
        return serial_port
# Did not find serial port (need to do something)

标签: pythonpython-2.7

解决方案


虽然可以拦截SerialPort构造函数以便SerialPort("UniqueName1")返回现有值(如果有)而不是创建新值,但1通常不是您想要做的。

最简单的解决方案是只存储串行端口的字典,但这需要每次手动查找:

if "UniqueName1" not in ports:
    ports["UniqueName1"] = SerialPort("UniqueName1")
some_observer = Observer(ports["UniqueName1"])

因此,您可能希望将 dict 设为私有并将访问封装在一个函数中:

def getport(name):
    if port not in _ports:
        ports[name] = SerialPort(name)
    return ports[name]

现在您只需调用该函数:

some_observer = Observer(getport("UniqueName1"))

您可以将此函数放在与您的SerialPortObserver类相同的模块中。

如果您可能有多个不同的名称到端口的映射,您可能希望将其包装在一个SerialPortManager类中,该类的实例具有一个self._ports和一个getport方法,否则您不需要它。


1.如果你真的想拦截构造函数,方法是使用__new__方法。默认实现只返回一个新的类型的空对象,如果你返回它,你的__init__方法就会被调用。但是你可以返回任何你想要的东西。其中包括不调用super()版本,而是在一些私有字典中查找值。


推荐阅读