требуется подобный байту объект / ord () ожидаемая строка длины 1, но найдена int (python 3.6) - PullRequest
0 голосов
/ 01 мая 2018

Я пытаюсь работать с: softScheck / TP-Link-SmartPlug

Я застрял в цикле ошибок. Исправление для первого вызывает другое, а исправление для другого - первое. Весь код находится в tplink-smartplug.py по ссылке git.

cmd = "{\"system\":{\"set_relay_state\":{\"state\":0}}}"

sock_tcp.send(encrypt(cmd))

def encrypt(string):
    key = 171
    result = "\0\0\0\0"
    for i in string: 
        a = key ^ ord(i)
        key = a
        result += chr(a)
    return result

На самом деле, результат = 'Ð ÿ ÷ ÿ ¶ ¶ ¶ ¶ è ° · · · è Ñ Ñ À À Ø Ø and and and', и я получаю ошибку (в строке 92 в исходном файле: sock_tcp.send (encrypt (cmd)):

требуется байтоподобный объект, а не 'str'

поэтому я тоже изменяю вызов функции:

sock_tcp.send(encrypt(cmd.encode('utf-8')))

и моя ошибка тоже меняется:

ord () ожидаемая строка длины 1, но найдено int

Я понимаю, что ord () пытается сделать, и понимаю кодировку. Но я не понимаю, как ... как я могу отправить это зашифрованное сообщение моему умному плагину, если я не могу дать компилятору то, что он хочет? Есть ли работа вокруг? Я почти уверен, что оригинальный git был написан на Python 2 или более ранней версии. Так что, возможно, я не правильно конвертирую в Python 3?

Спасибо за чтение, я ценю любую помощь.

1 Ответ

0 голосов
/ 01 мая 2018

В Python 2 результатом encode является str строка байтов, которая представляет собой последовательность 1-байтовых str значений. Итак, когда вы делаете for i in string:, каждый i является str, и вам нужно позвонить ord(i), чтобы превратить его в число от 0 до 255.

В Python 3 результатом encode является bytes строка байтов, которая представляет собой последовательность 1-байтовых целых чисел. Поэтому, когда вы делаете for i in string:, каждый i уже равен int от 0 до 255, поэтому вам не нужно ничего делать, чтобы преобразовать его. (И, если вы все равно попытаетесь это сделать, вы получите TypeError, который вы видите.)

Между тем, вы строите result как str. В Python 2 это нормально, но в Python 3 это означает, что это Unicode, а не байты. Отсюда и другие TypeError, которые вы видите.

Для получения более подробной информации о том, как перенести код обработки строк Python 2 в Python 3, вы должны прочитать Руководство по портированию, особенно Текст в сравнении с двоичными данными и, возможно, Unicode HOWTO если вам нужно больше фона.


Один из способов написания кода для одинаковой работы для Python 2 и 3 - использовать bytearray для обоих значений:

def encrypt(string):
    key = 171
    result = bytearray(b"\0\0\0\0")
    for i in bytearray(string): 
        a = key ^ i
        key = a
        result.append(a)
    return result

cmd = u"{\"system\":{\"set_relay_state\":{\"state\":0}}}"

sock_tcp.send(encrypt(cmd.encode('utf-8')))

Обратите внимание на префикс u в cmd, который гарантирует, что это Unicode даже в Python 2, и префикс b в result, который гарантирует, что это байты даже в Python 3. Хотя, как вы знаете, cmd - это чистый ASCII, может быть проще сделать это:

cmd = b"{\"system\":{\"set_relay_state\":{\"state\":0}}}"

sock_tcp.send(encrypt(cmd))

Если вас не волнует Python 2, вы можете просто за for i in string: не преобразовать его в bytearray, но вы все равно, вероятно, захотите использовать его для result. (Возможность append int напрямую к нему делает более простой код - и это еще более эффективно, как приятный бонус.)

...