Readline() приводит к совместимости pyserial python 2 и 3

Я пишу простой код для связи с несколькими идентичными устройствами RS-232 с помощью pyserial. Отправляю команду и получаю ответ. 6-й элемент в ответе — это мой ID. Этот идентификатор используется для определения того, с каким устройством я разговариваю.

Я хочу иметь более элегантный синтаксис, который извлекает 6-й элемент как целое число как в Python 3, так и в Python 2. Есть ли более элегантный способ, чем просто написать две разные функции, которые я вызываю в зависимости от того, какой Python используется.

В случае 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
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
449
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Результатом port.readline() являются двоичные данные (называемые str в Python 2, bytes в Python 3). Таким образом, вопрос заключается в том, как обрабатывать двоичные данные совместимым с Python 2 и Python 3 способом. Есть несколько способов сделать это. Следующие три решения дают одинаковый результат (число = 52) для Python 2 и 3.

ДЛЯ ДВОИЧНЫХ ДАННЫХ

Решение 1

Если вы знаете, как кодируются данные, вы можете правильно их раскодировать. Это приведет к «текстовой строке Unicode» (называется unicode в Python 2, str в Python 3).

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 is a Python 2 and 3 compatibility library. It provides utility functions for smoothing over the differences between the Python versions with the goal of writing Python code that is compatible on both Python versions. See the documentation for more information on what is provided.

Например:

import six

reply = b'\xff/0`ZA4\x03\r\n'
number = six.byte2int(reply[6:7])

Обратите внимание, что эта библиотека также предоставляет решения для многих других проблем совместимости. Поэтому, если вы пишете более крупное приложение, которое должно быть совместимо с Python 2 и 3, на него, безусловно, стоит обратить внимание.

ДЛЯ ДАННЫХ ASCII

Если ваш идентификатор представляет собой число в кодировке ASCII в диапазоне от 0 до 9, лучшим решением будет следующее решение. Использование 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'))

Число будет равно 4 как в Python 2, так и в 3.

В качестве альтернативы вы можете использовать одно из «двоичных» решений и вычесть из результата 48 (= символ ASCII «0»).

(Все приведенные выше примеры были протестированы с Python 2.7 и 3.7)

Спасибо за 3 возможных решения. Однако только первый работает как в Python 2, где readline() возвращает строку, так и в Python 3, где ответом являются байты. Решение 3 в Python 3: IIn [25]: six.byte2int(b'\xff/0ZA4\x03\r\n'[6:7]) Out[25]: 52; Solution 2 in Python2: In [8]: struct.unpack('B','\xff/0ZA4\x03\r\n'[6:7]) Out[8]: (52,) ; Решение 1 в Python 2: В [9]: '\xff/0ZA4\x03\r\n'.decode('latin-1')[6] Out[9]: u'4' Solution 1 in Python 3:In [26]: b'\xff/0ZA4\x03\r\n'.decode('latin-1')[6] Out[26]: '4'

Valentyn 21.06.2019 05:50

Отредактировано позже: так что все 3 будут работать, но это не выглядит красиво. Например, решение № 3 выглядит так: Python 3: In [31]: int(chr(six.byte2int(b[6:7])) )) Out[31]: 4 и Python 2: In [13]: int (chr(six.byte2int('\xff/0`ZA4\x03\r\n'[6:7]))) Выход[13]: 4

Valentyn 21.06.2019 06:00

@ Валентин, я не понимаю, что ты имеешь в виду. Я протестировал все три приведенных выше примера с Python 2.7 и Python 3.7 (в Python 2.7 вы могли написать '\xff..' вместо b'\xff..', чтобы точно соответствовать полученному ответу, но результат тот же). В вашем последнем примере вы фактически делаете int(chr(52)), что равно 4. Почему вы это делаете? Я не могу протестировать код с реальным модулем pyserial, но, учитывая reply, как указано в вашем вопросе, во всех трех решениях переменная number получит значение 52 в Python 2 и 3. Разве это не ожидаемый результат? Вы хотите, чтобы он вместо этого возвращал 4?

wovano 21.06.2019 08:28

@ Валентин, я обновил свой ответ. Пожалуйста, дайте мне знать, если это то, что вы ожидали.

wovano 21.06.2019 08:46

Другие вопросы по теме