Python 2到3的迁移过程-关于Unicode的差异

问题描述 投票:0回答:1

我正在尝试将代码从Python2迁移到Python3,因为不再支持Python2。但是,由于两个版本之间的差异,我在迁移过程中遇到了困难。我知道Python2曾经同时具有字符串和unicode对象,而Python3默认存储的字符串是unicode。

在我的代码中的某个地方,我将元组的十六进制表示形式存储在数据库中。我从用户填写的表单中获取此元组,其中一个值是unicode类型。由于Python3在字符串和Unicode之间没有区别,我最终得到了包含相同值的元组的不同十六进制表示形式。

这是显示我的问题的代码段:

Python2-

In [1]: from hashlib import sha1

In [2]: cred = ('user', 'pass')

In [3]: sha1(str(cred)).hexdigest()
Out[3]: '7cd99ee437e8166559f55a0336d4b48d9bc62bb2'

In [4]: unicode_cred = ('user', u'pass')

In [5]: sha1(str(unicode_cred)).hexdigest()
Out[5]: '807a138ff9b0dd6ce6a937e3df3bba3223b40fcd'

Python3-

In [1]: from hashlib import sha1                                                

In [2]: cred = ('user', 'pass')                                                 

In [3]: sha1(str(cred)).hexdigest()                                             
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-3-847e91fdf4c5> in <module>
----> 1 sha1(str(cred)).hexdigest()

TypeError: Unicode-objects must be encoded before hashing

In [4]: sha1(str(cred).encode('utf-8')).hexdigest()                             
Out[4]: '7cd99ee437e8166559f55a0336d4b48d9bc62bb2'

In [5]: unicode_cred = ('user', u'pass')                                        

In [6]: sha1(str(unicode_cred).encode('utf-8')).hexdigest()                     
Out[6]: '7cd99ee437e8166559f55a0336d4b48d9bc62bb2'

您可以看到,在Python2中,Out[3]Out[5]的值不同,而在Python3中,Out[4]Out[6]相同。

是否有一种方法可以再现Out[5]的值,如Python2片段所示?在迁移过程中,我需要确保相同的输入产生相同的输出,因此我不会在数据库中插入新记录,而不会更新现有记录。

python python-3.x unicode python-2.x
1个回答
1
投票

使用str()输出的十六进制摘要是问题。 str()是一个与版本有关的字符串,您需要完全相同的表示形式来形成十六进制摘要:

Python 2

>>> unicode_cred = ('user', u'pass')
>>> str(unicode_cred)
"('user', u'pass')"

Python 3(请注意缺少的'u')。 str()的输出也是Python 3上的Unicode字符串,因此必须将其编码为字节才能与sha1()一起使用。 b不是字符串的一部分,仅表示它现在是字节字符串。

>>> unicode_cred = ('user', u'pass')
>>> str(unicode_cred).encode('utf-8')
b"('user', 'pass')"

您需要与u组成相同的字符串以获取相同的摘要,这有点难看。在这里,我使用f字符串自定义格式为u的元组。我还使用ascii进行编码,因为非ASCII字符会引起其他问题。希望您没有非ASCII的用户名和密码。

>>> from hashlib import sha1
>>> unicode_cred = ('user', u'pass')
>>> f"('{unicode_cred[0]}', u'{unicode_cred[1]}')"
"('user', u'pass')"
>>> sha1(f"('{unicode_cred[0]}', u'{unicode_cred[1]}')".encode('ascii')).hexdigest()
'807a138ff9b0dd6ce6a937e3df3bba3223b40fcd'
© www.soinside.com 2019 - 2024. All rights reserved.