我正在编写一个简单的代码,以使用pyserial与多个相同的RS-232设备进行通信。我发送命令并得到答复。回复中的第六个元素是我的ID。此ID用于定义我正在与之通信的设备。
我想拥有一种更优雅的语法,在Python 3和Python 2中都将第6个元素提取为整数。是否有一种更优雅的方式,然后根据所使用的Python编写我调用的两个不同函数。 / p>
对于Python 3
>>> port = Serial('/dev/cu.usbserial4')
>>> port.baudrate = 9600
>>> port.timeout = 0.4
>>> port.write(b"/1?80\r")
6
>>> reply = port.readline()
>>> reply
b'\xff/0`ZA4\x03\r\n'
>>> reply[6]
52
>>> chr(reply[6])
'4'
>>> int(chr(reply[6]))
4
对于Python 2
>>> port = Serial('/dev/cu.usbserial4')
>>> port.baudrate = 9600
>>> port.timeout = 0.4
>>> port.write(b"/1?80\r")
6
>>> reply = port.readline()
>>> reply
'\xff/0`ZA4\x03\r\n'
>>> reply[6]
'4'
>>> int(reply[6])
4
答案 0 :(得分:1)
port.readline()
的结果是二进制数据(在Python 2中称为str
,在Pyton 3中称为bytes
)。因此,问题是如何以Python 2和Python 3兼容的方式处理二进制数据。有多种方法可以做到这一点。以下三个解决方案对于Python 2和3都给出相同的结果(数字= 52)。
用于二进制数据
解决方案1
如果您知道数据的编码方式,则可以正确解码。这将导致“ unicode文本字符串”(在Python 2中称为unicode
在Python 3中为str
)。
reply = b'\xff/0`ZA4\x03\r\n'
decoded_reply = reply.decode('latin-1')
number = ord(decoded_reply[6])
解决方案2
更通用的解决方案是使用struct
模块来解码二进制数据:
import struct
reply = b'\xff/0`ZA4\x03\r\n'
number = struct.unpack('B', reply[6:7])[0]
解决方案3
您还可以使用six
模块:
Six是Python 2和3的兼容性库。它提供了一些实用程序函数,用于消除Python版本之间的差异,目的是编写在两个Python版本上都兼容的Python代码。有关提供的内容的更多信息,请参见文档。
例如:
import six
reply = b'\xff/0`ZA4\x03\r\n'
number = six.byte2int(reply[6:7])
请注意,该库还提供了许多其他兼容性问题的解决方案。因此,如果您要编写一个需要与Python 2和3兼容的更大的应用程序,那肯定值得研究。
用于ASCII数据
如果您的ID是0-9范围内的ASCII编码数字,则以下解决方案将是最佳选择。在这种情况下,使用struct
毫无意义。
reply = '\xff/0`ZA4\x03\r\n' # input in Python 2
reply = b'\xff/0`ZA4\x03\r\n' # input in Python 3
number = int(reply.decode('latin-1')[6])
# or if your reply is mixed binary and ASCII and you're only interested in byte 6:
number = int(reply[6:7].decode('ascii'))
在Python 2和3中,数字均为4。
或者,您可以使用“二进制”解决方案之一,并从结果中减去48(= ASCII字符“ 0”)。
(以上所有示例均已使用Python 2.7和3.7进行了测试)