Python 练习讲解 · 22 / 25

二、八、十、十六进制互转

先把输入读成整数,再用自己写的除基取余函数转成目标进制。

要学习的知识点

题目

补充练习:在二、八、十、十六进制之间进行任意方向转换。

输入:数值字符串(十六进制可用 A-F)、原进制、目标进制;进制均为 2、8、10、16。

参考程序:ex22.py;空白练习:lx22.py。

完整代码

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

"""补充练习:在二、八、十、十六进制之间进行任意方向转换。
输入:数值字符串(十六进制可用 A-F)、原进制、目标进制;进制均为 2、8、10、16。

学习说明:
- to_base() 将非负十进制整数转成目标进制;divmod() 每次给出商和余数。
- 余数对应当前最低位,因此收集后要倒序;数字字母表支持十六进制的 A 到 F。
- int(text, source_base) 是 Python 提供的输入解析方式,先把原进制数值转成整数。
- 转换到目标进制时调用自己写的 to_base(),练习“除基取余”算法。
"""
DIGITS = "0123456789ABCDEF"


def to_base(number, base):
    # 用字符表把余数 0~15 转换成相应的数字符号。
    if number == 0:
        return "0"
    result = []
    while number:
        number, remainder = divmod(number, base)
        result.append(DIGITS[remainder])
    return "".join(reversed(result))


text = input().strip()
source_base, target_base = map(int, input().split())
valid_bases = {2, 8, 10, 16}
if source_base not in valid_bases or target_base not in valid_bases:
    raise ValueError("进制只能是 2、8、10 或 16")

value = int(text, source_base)
if value < 0:
    raise ValueError("本练习只处理非负整数")
print(to_base(value, target_base))

进阶写法

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

进阶源码:ex22_adv.py

"""练习 22 进阶版:使用 int 的进制解析和 format 格式化转换。"""
text = input().strip()
source_base, target_base = map(int, input().split())
if source_base not in {2, 8, 10, 16} or target_base not in {2, 8, 10, 16}:
    raise ValueError("进制只能是 2、8、10 或 16")

number = int(text, source_base)
if number < 0:
    raise ValueError("本练习只处理非负整数")

format_codes = {2: "b", 8: "o", 10: "d", 16: "X"}
print(format(number, format_codes[target_base]))

int(text, base) 按原进制解析;字典把目标进制映射到 format() 的格式符,避免自己编写除基取余转换。

运行结果

示例输入:

FF
16 2

程序输出:

11111111

逐个认识函数

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

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

两阶段转换

  1. 检查原进制和目标进制都属于 {2, 8, 10, 16}。
  2. int(text, source_base) 把输入文本解释成整数,例如 int("FF",16) 得 255。
  3. 把十进制整数交给 to_base(number, base)。
  4. to_base 反复除以目标进制,收集余数,倒序拼成字符串。

十进制在此只是程序内部的统一数值表示。Python 的 int 与进制无关;整数文本前缀或传入 base 才说明如何解析文字。

自定义函数和内置函数

函数参数与返回值细节
to_base(number, base)参数为非负整数和目标基数;返回目标进制字符串。0 单独返回 "0";非零值循环除基数,余数用于索引 DIGITS 字符表。
int(text, base)内置函数;按 base 解释 text 并返回整数。base 为 2–36 或 0;本题白名单只允许 2、8、10、16。非法数字会 ValueError。
str.strip()无参数移除首尾空白,返回新字符串。允许输入前后有空格;不会移除中间空白。
input().split()读取一行并按空白拆开,返回文本列表。进制行需要恰好两个整数。
divmod(number, base)返回商与余数的二元组。本题算法用它同时取得下一位和剩余商。
reversed(items)返回反向迭代器。余数产生顺序与书写位序相反,必须反转。
str.join(iterable)将一串字符串片段用调用者字符串作为分隔符连接,返回 str。"".join(...) 表示无分隔连接。

手算 26 转十六进制

26 ÷ 16 = 1 余 10 → DIGITS[10] 是 A
1  ÷ 16 = 0 余 1  → DIGITS[1] 是 1
余数倒序读:1A

当前函数设计给非负数和 2–16 范围内的 base 使用;主程序负责输入非负数和限定进制。本题十六进制字母表为大写 A–F。

代码如何运行

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

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

自己动手试一试

试试 0、FF 转十进制、二进制转十六进制,以及输入不合法数字时的错误。

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