数字类型实战——十六进制、八进制、二进制:字面量和转换

未匹配的标注

除了到目前为止一直在使用的普通的底数为10的十进制外,Python整数还能用十六进制、八进制、二进制的表示法来编码。后面这三个进制对10个手指的生物来说可能一开始是陌生的,但一些程序员发现它们是指定值的方便的替代方法,特别是当这些值到字节和比特的映射很重要时。在本章开头编码规则就被简要介绍了,在这里看一些实际的例子。

记住这些字面量仅仅是指定整数对象值的可选语法。比如,下面在Python 3系列或2系列中编码的字面量以在所有三个底数(进制)的指定值产生了普通整数。在内存中,不管用来指定它的底数是哪个,整数的值是相同的:

>>> 0o1, 0o20, 0o377 # 八进制字面量: 底数为 8, 数字符号为 0-7 (3.X, 2.6+)
(1, 16, 255)
>>> 0x01, 0x10, 0xFF # 十六进制字面量: 底数为 16, 数字符号为 0-9/A-F (3.X, 2.X)
(1, 16, 255)
>>> 0b1, 0b10000, 0b11111111 # 二进制字面量: 底数为 2, 数字符号为 0-1 (3.X, 2.6+)
(1, 16, 255)

这里的八进制值0o377,十六进制值0xFF,二进制值0b11111111都是十进制255。比如,在十六进制值中的F数字符号,每一个在十进制中是15,在二进制中是一个4比特的1111,而且代表了16的幂的倍数。因此,十六进制数0xFF和其他数如下转换为十进制值:

>>> 0xFF, (15 * (16 ** 1)) + (15 * (16 ** 0)) # 十六进制/二进制数如何映射到十进制
(255, 255)
>>> 0x2F, (2 * (16 ** 1)) + (15 * (16 ** 0))
(47, 47)
>>> 0xF, 0b1111, (1*(2**3) + 1*(2**2) + 1*(2**1) + 1*(2**0))
(15, 15, 15)

Python默认以十进制(底数为10)打印整数,但提供了内置函数来将整数转换为其他底数的数字字符串,以Python字面量的形式——当程序或用户期待以给定底数来显示值时很有用:

>>> oct(64), hex(64), bin(64) # 数字=>数字符号字符串
('0o100', '0x40', '0b1000000')

oct函数将十进制转换为八进制,hex函数转换为十六进制,bin函数转换为二进制。反过来,内置int函数将数字字符串转换为整数,可选的第二参数指定数字底数——对于从文件里读作字符串,而不是编码在脚本中的数字很有用:

>>> 64, 0o100, 0x40, 0b1000000 # 数字符号=>在脚本和字符串中的数字
(64, 64, 64, 64)
>>> int('64'), int('100', 8), int('40', 16), int('1000000', 2)
(64, 64, 64, 64)
>>> int('0x40', 16), int('0b1000000', 2) # 也支持字面量形式
(64, 64)

在本书后面会遇到的 eval函数将字符串像Python代码那样处理。因此,它效果和前面的例子类似,但通常运行得得多——事实上它编译并运行字符串作为程序的一部分,且它假设被允许的字符串来自可信任源——聪明的用户可能会提交一个字符串来删除你机器上的文件,所以小心使用这个调用:

>>> eval('64'), eval('0o100'), eval('0x40'), eval('0b1000000')
(64, 64, 64, 64)

最后,还可以使用字符串格式化方法调用和表达式(它们只返回数字符号,而非Python字面量字符串)来将整数转换为特定底数的字符串:

>>> '{0:o}, {1:x}, {2:b}'.format(64, 64, 64) # 数字=>数字符号, 2.6+
'100, 40, 1000000'
>>> '%o, %x, %x, %X' % (64, 64, 255, 255) # 在所有Python中类似
'100, 40, ff, FF'

字符串格式化在第7章会更详细介绍。

在继续学习前注意两点。首先,根据本章开头,Python 2系列的用户应该记得可以只用一个前导0(Python中原来的八进制格式)来编码八进制数:

>>> 0o1, 0o20, 0o377 #  在 2.6+ 中的新八进制格式(同 3.X 相同)
(1, 16, 255)
>>> 01, 020, 0377 # 在所有 2.X 中的老的八进制格式(在 3.X 会出错)
(1, 16, 255)

在3系列中,这些例子中的第二个产生了一个错误。即使在2系列中它不是一个错误,也要小心不要用一个前导零开始一串数字符号,除非真的想编码一个八进制的值。Python 2系列将会作为底数8来处理,这可能不会如预期那样工作——010在系列2中总是十进制8,而非十进制10(不管你怎么想!)这(再加上要和十六进制和二进制形式保持统一)就是在系列3中八进制格式变化的原因——在3系列中必须使用0o010,在2.6和2.7中为了清楚和与系列3保持向前兼容,很可能也应该使用。

第二,注意这些字面量可以产生任意长的整数。比如,下面用十六进制标记创建了一个整数,然后先用十进制显示它,再用转换函数以八进制和二进制显示(这里是在3系列中运行:在2系列中,十进制和八进制显示会有一个尾随的L来表明它独特的长整型,而且八进制的显示没有字母o):

>>> X = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF
>>> X
5192296858534827628530496329220095
>>> oct(X)
'0o17777777777777777777777777777777777777'
>>> bin(X)
'0b111111111111111111111111111111111111111111111111111111111 ...等等... 11111'

说到二进制数字符号,下一节将显示处理单个字节的工具。

本文章首发在 LearnKu.com 网站上。

上一篇 下一篇
讨论数量: 0
发起讨论 只看当前版本


暂无话题~