【问题标题】:AttributeError:'bytes' object has no attribute 'encode'AttributeError:'bytes' 对象没有属性 'encode'
【发布时间】:2020-02-24 02:50:44
【问题描述】:

尝试将代码从python2导入python 3,出现这个问题

    <ipython-input-53-e9f33b00348a> in aesEncrypt(text, secKey)
     43 def aesEncrypt(text, secKey):
     44     pad = 16 - len(text) % 16
---> 45     text = text.encode("utf-8") + (pad * chr(pad)).encode("utf-8")
     46     encryptor = AES.new(secKey, 2, '0102030405060708')
     47     ciphertext = encryptor.encrypt(text)

AttributeError:'bytes' 对象没有属性 'encode'

如果我删除 .encode("utf-8") 错误是“无法将 str 连接到字节”。显然pad*chr(pad) 似乎是一个字节串。它不能使用encode()

    <ipython-input-65-9e84e1f3dd26> in aesEncrypt(text, secKey)
     43 def aesEncrypt(text, secKey):
     44     pad = 16 - len(text) % 16
---> 45     text = text.encode("utf-8") + (pad * chr(pad))
     46     encryptor = AES.new(secKey, 2, '0102030405060708')
     47     ciphertext = encryptor.encrypt(text)

TypeError: can't concat str to bytes

然而,奇怪的是,如果我只是尝试这个部分。 encode() 工作正常。

text = { 'username': '', 'password': '', 'rememberLogin': 'true' }
text=json.dumps(text)
print(text)
pad = 16 - len(text) % 16 
print(type(text))
text = text + pad * chr(pad) 
print(type(pad * chr(pad)))
print(type(text))
text = text.encode("utf-8") + (pad * chr(pad)).encode("utf-8") 
print(type(text))

{"username": "", "password": "", "rememberLogin": "true"}
<class 'str'>
<class 'str'>
<class 'str'>
<class 'bytes'>

【问题讨论】:

  • chr 返回一个字符串,该字符串被相乘并编码为字节。这里的问题是text 是字节。你怎么打电话给aesEncrypt?您需要提供minimal reproducible example
  • Python2 字符串是隐式字节对象,而 Python3 字符串是 unicode。所以这是有道理的。这对我来说似乎是正确的方法 - 您添加 .encode('utf-8') 的方式。但这不会与 Python2 向后兼容——这就是问题所在吗? @RoyDai
  • 也许一种控制编解码器的便携方式是导入codec并使用它的encode()decode()模块函数。
  • pad = 16 - len("dummy") % 16; (pad * chr(pad)).encode('utf-8') b'\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b' 在 Python3 上运行良好.. 除非存在无法编码的填充字节。
  • @Todd 非常感谢您的回复。我试过 .encode('utf-8') 适用于隔离会话,但它不适用于第一种情况,我现在不知道为什么。

标签: python python-2to3


【解决方案1】:

如果您不知道类似字符串的对象是 Python 2 字符串(字节)还是 Python 3 字符串(unicode)。你可以有一个通用转换器。

Python3 外壳:

>>> def to_bytes(s):
...     if type(s) is bytes:
...         return s
...     elif type(s) is str or (sys.version_info[0] < 3 and type(s) is unicode):
...         return codecs.encode(s, 'utf-8')
...     else:
...         raise TypeError("Expected bytes or string, but got %s." % type(s))
...         
>>> to_bytes("hello")
b'hello'
>>> to_bytes("hello".encode('utf-8'))
b'hello'

在 Python 2 上,这两个表达式的计算结果都为 Truetype("hello") == bytestype("hello") == str。而type(u"hello") == str 的计算结果为False,而type(u"hello") == unicodeTrue

在 Python 3 上,type("hello") == bytesFalsetype("hello") == strTrue。并且type("hello") == unicode 引发NameError 异常,因为unicode 未在3 上定义。

Python 2 外壳:

>>> to_bytes(u"hello")
'hello'
>>> to_bytes("hello")
'hello'

【讨论】:

    【解决方案2】:

    感谢@Todd,他解决了问题。 (pad * chr(pad))是字节,而问题在于aesEncrypt(text, secKey)。它被调用了两次,第一次是text,第一次是str,第二次是bytes

    解决方案是确保输入 textstr 类型。

    【讨论】:

      【解决方案3】:

      由于AES.new的第一个参数是bytes/bytearray/memoryview,并且我假设text已经是bytes类型,那么我们只需要将pad部分从unicode转换为bytes .

      text = text + (pad * chr(pad)).encode("utf-8")
      

      为了更加安全,您可以在与 pad 连接之前有条件地对 text 进行编码。

      if not isinstance(text, bytes):
          text = text.encode('utf-8')
      

      【讨论】:

      • @Todd 如何检查它是否不是字节?有点懒,但考虑到输入是字节或 unicode 会起作用
      • 你抓住了我,因为我刚刚完成了对这种差异的剖析 - 测试它是否不是字节会留下它可能是 None 或其他不是 str 或 unicode 对象的类型。看看你是否可以在我的答案帖的笔记中找到答案。让我知道我是否考虑了您的想法。
      猜你喜欢
      • 1970-01-01
      • 2020-07-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-03-28
      • 2021-04-23
      • 1970-01-01
      • 2020-11-04
      相关资源
      最近更新 更多