Python 练习讲解 · 16 / 25

进制转换:除基取余

反复除以目标进制,余数从低位到高位出现,所以要倒着读。

要学习的知识点

题目

练习 16:将十进制非负整数转换为二进制、八进制和十六进制。

转换过程通过反复除基数实现,不调用内置进制格式化函数。

参考程序:ex16.py;空白练习:lx16.py。

完整代码

以下内容与 ex16.py 一致,可对照右侧讲解阅读。

"""练习 16:将十进制非负整数转换为二进制、八进制和十六进制。
转换过程通过反复除基数实现,不调用内置进制格式化函数。

学习说明:
- convert_to_base(number, base) 是转换函数;digits 字符串提供 0 到 15 的数字符号。
- 每次除以 base,余数就是当前最低位;继续处理商,直到商为 0。
- 余数是从低位到高位得到的,所以最后需要 reversed() 倒转顺序。
- 0 要单独处理,否则循环不会运行且结果列表为空。
"""
def convert_to_base(number, base):
    digits = "0123456789ABCDEF"
    if number == 0:
        return "0"

    # 先按从低位到高位收集每次除法得到的余数。
    result = []
    while number > 0:
        number, remainder = divmod(number, base)
        result.append(digits[remainder])
    return "".join(reversed(result))


number = int(input())
if number < 0:
    raise ValueError("请输入非负整数")

print("binary:", convert_to_base(number, 2))
print("octal:", convert_to_base(number, 8))
print("hexadecimal:", convert_to_base(number, 16))

进阶写法

这版与初学版解决同一道题,使用更精炼的语法或标准库工具。

进阶源码:ex16_adv.py

"""练习 16 进阶版:用 format 的进制格式符直接转换整数。"""
number = int(input())
if number < 0:
    raise ValueError("请输入非负整数")

print("binary:", format(number, "b"))
print("octal:", format(number, "o"))
print("hexadecimal:", format(number, "X"))

format(number, 'b'/'o'/'X') 直接返回二、八、十六进制文本;X 表示大写十六进制,不包含 0x 前缀。

运行结果

示例输入:

26

程序输出:

binary: 11010
octal: 32
hexadecimal: 1A

逐个认识函数

下表根据程序中实际调用的函数和方法整理;自定义函数的实现与算法细节见后续说明。

函数形式功能与返回值注意事项
separator.join(iterable)用 separator 将多个字符串连接成一个新字符串。每一项都必须是字符串;空字符串作为分隔符时不会插入字符。
ValueError(message)内置异常类型,用来表示参数值不符合要求。raise ValueError(...) 会立即抛错并停止当前程序流程。
convert_to_base(number, base)本题自定义函数:返回非负整数在目标进制下的字符串。通过 divmod 取余;收集数字后需要逆序。
divmod(a, b)返回二元组 (a // b, a % b),即商和余数。除数 b 不能为 0。
input(prompt='')读取一行文本,返回 str;若提供 prompt 会先显示提示。返回值默认是字符串,计算前通常要做类型转换。
int(value, base=10)把整数文本或数值转换为整数。int('3.5') 不合法;按指定进制解析时可传 base。
print(*objects, sep=' ', end='\n')把对象转换为文本显示;返回 None。默认空格分隔并在末尾换行。
list.append(item)在列表末尾追加一个元素;返回 None。会原地修改列表。
reversed(sequence)返回反向迭代器,不修改原序列。可配合 ''.join() 逆序拼接字符。

自定义函数 to_base

def convert_to_base(number, base):
项目说明
参数 number要转换的十进制非负整数。
参数 base目标基数。本题使用 2、8、16。
返回值表示转换结果的字符串,例如 "11010" 或 "1A"。
边界number 为 0 时直接返回 "0",因为 0 没有非零位可供循环收集。

函数通过 divmod(number, base) 同时得到商和余数。余数对应当前最低位,使用 DIGITS[remainder] 找到对应符号,然后把商作为下一轮的 number。

相关函数与方法

写法参数 / 返回说明
divmod(a, b)返回 (a//b, a%b) 的二元组。每轮取得下一位余数和待处理的商。
list.append(value)在列表末尾添加一项,返回 None。余数从低位开始加入 result。
reversed(iterable)返回反向迭代器,不会改动原容器。把低位到高位的字符倒过来读取。
"".join(iterable)字符串方法;把多个字符串连接成一个字符串并返回。空字符串作为分隔符,因此字符之间不会插入额外内容。
int(input())读取并转换十进制整数。程序只接受非负数;负数将引发 ValueError。

十六进制的数字表

十六进制需要 16 个符号:0–9 表示 0–9,A–F 表示 10–15。代码字符串 "0123456789ABCDEF" 用下标查符号,所以 remainder=10 时取到 A。

试试把 0、1、15、16、26 分别转换成 2、8、16 进制。特别检查 0 和出现 A–F 的值。

代码如何运行

  1. 先按左侧题目给出的格式输入数据;程序通过 input() 读取,并在需要时转换数据类型。
  2. 程序自上而下执行语句;遇到条件、循环或函数调用时,按照右侧算法说明更新变量和处理数据。
  3. 最后由 print() 输出计算结果。可将左侧示例输入与输出逐项对照。

先自己跟踪一组小数据,记录循环前后变量的值;这比只看最终答案更容易理解程序。

自己动手试一试

测试 0、15、16、26;检查十六进制 A–F,以及 0 的特殊处理。

先在 lx16.py 中独立完成,再运行参考程序比较结果。修改程序时一次只改一个条件或步骤。