readline()导致pyserial python 2和3兼容

时间:2019-06-20 19:15:45

标签: python-3.x python-2.7 pyserial

我正在编写一个简单的代码,以使用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

1 个答案:

答案 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进行了测试)