python散装笔记——149: 从Python 2迁移到Python 3的不兼容性(六)
26: 编码/解码为十六进制不再可用
Python 2.x Version ≤ 2.7
"1deadbeef3".decode('hex')
# Out: '\x1d\xea\xdb\xee\xf3'
'\x1d\xea\xdb\xee\xf3'.encode('hex')
# Out: 1deadbeef3
Python 3.x Version ≥ 3.0
"1deadbeef3".decode('hex')
# Traceback (most recent call last):
# File "", line 1, in
# AttributeError: 'str' object has no attribute 'decode'
b"1deadbeef3".decode('hex')
# Traceback (most recent call last):
# File "", line 1, in
# LookupError: 'hex' is not a text encoding; use codecs.decode() to handle arbitrary codecs
'\x1d\xea\xdb\xee\xf3'.encode('hex')
# Traceback (most recent call last):
# File "", line 1, in
# LookupError: 'hex' is not a text encoding; use codecs.encode() to handle arbitrary codecs
b'\x1d\xea\xdb\xee\xf3'.encode('hex')
# Traceback (most recent call last):
# File "", line 1, in
# AttributeError: 'bytes' object has no attribute 'encode'
然而,正如错误消息所建议的那样,你可以使用codecs模块来实现相同的结果:
import codecs
codecs.decode('1deadbeef4', 'hex')
# Out: b'\x1d\xea\xdb\xee\xf4'
codecs.encode(b'\x1d\xea\xdb\xee\xf4', 'hex')
# Out: b'1deadbeef4'
注意,codecs.encode返回一个字节对象。要获得字符串对象,只需解码为ASCII:
codecs.encode(b'\x1d\xea\xdb\xee\xff', 'hex').decode('ascii')
# Out: '1deadbeeff'
27: 字典方法更改
在Python 3中,许多字典方法的行为与Python 2不同,许多方法也被移除了:has_key、iter*和view*。作为d.has_key(key)的替代,现在必须使用key in d。
在Python 2中,字典方法keys、values和items返回列表。在Python 3中,它们返回视图对象;视图对象不是迭代器,它们与迭代器有两点不同,即:
- 它们有大小(可以使用len函数)
- 它们可以多次迭代
此外,与迭代器一样,字典中的更改会反映在视图对象中。
Python 2.7从Python 3中回退了这些方法;它们分别可用作viewkeys、viewvalues和viewitems。要将Python 2代码转换为Python 3代码,相应的形式是:
- Python 2中的d.keys()、d.values()和d.items()应更改为list(d.keys())、list(d.values())和list(d.items())
- Python 2中的d.iterkeys()、d.itervalues()和d.iteritems()应更改为iter(d)、iter(d.values())和iter(d.items())
- 最后,Python 2.7中的方法调用d.viewkeys()、d.viewvalues()和d.viewitems()可以替换为d.keys()、d.values()和d.items()
将Python 2代码转换为Python 3代码时,有时会比较棘手,尤其是在迭代字典的键、值或项时进行修改。考虑以下代码:
d = {'a': 0, 'b': 1, 'c': 2, '!': 3}
for key in d.keys():
if key.isalpha():
del d[key]
代码看起来像是在Python 3中也会类似地工作,但在这里,keys方法返回的是视图对象,而不是列表,如果在迭代过程中字典大小发生变化,Python 3代码将因RuntimeError而崩溃:在迭代过程中字典大小发生了变化。解决方案当然是正确地写成for key in list(d)。
同样,视图对象的行为与迭代器不同:不能在它们上使用next(),并且不能恢复迭代;相反,它会重新开始;如果Python 2代码将d.iterkeys()、d.itervalues()或d.iteritems()的返回值传递给一个期望迭代器而不是可迭代对象的方法,那么在Python 3中应该是iter(d)、iter(d.values())或iter(d.items())。
28: 类布尔值
Python 2.x Version ≤ 2.7
在Python 2中,如果你想自己定义类的布尔值,你需要在你的类中实现__nonzero__方法。默认值为True。
class MyClass:
def __nonzero__(self):
return False
my_instance = MyClass()
print bool(MyClass) # True
print bool(my_instance) # False
Python 3.x Version ≥ 3.0
在Python 3中,使用__bool__而不是__nonzero__。
class MyClass:
def __bool__(self):
return False
my_instance = MyClass()
print(bool(MyClass)) # True
print(bool(my_instance)) # False
29: Python 2中hasattr函数的错误
在Python 2中,当属性引发错误时,hasattr会忽略该属性,返回False。
class A(object):
@property
def get(self):
raise IOError
class B(object):
@property
def get(self):
return 'get in b'
a = A()
b = B()
print 'a hasattr get: ', hasattr(a, 'get')
# output False in Python 2 (fixed, True in Python 3)
print 'b hasattr get', hasattr(b, 'get')
# output True in Python 2 and Python 3
此错误已在Python 3中修复。因此,如果你使用的是Python 2,可以使用以下代码:
try:
a.get
except AttributeError:
print("no get property!")
或者使用getattr代替:
p = getattr(a, "get", None)
if p is not None:
print(p)
else:
print("no get property!")