# 练习 26:`hexdump`
> 原文:[Exercise 26: hexdump](https://learncodethehardway.org/more-python-book/ex26.html)
> 译者:[飞龙](https://github.com/wizardforcel)
> 协议:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/)
> 自豪地采用[谷歌翻译](https://translate.google.cn/)
你已经用`xargs`完成了热身,现在正在代码/审计的循环中。你现在将尝试以“测试优先”方式完成下一个挑战。这就是,你编写测试,它描述你的预期行为,然后实现该行为,直到通过测试。你将要复制`hexdump`工具,并尝试将你的版本的输出与真实版本匹配。这是“测试优先”开发真正有帮助的地方,因为它自动化了模仿另一个软件的流程。
当你需要编写一个糟糕的软件的替代品时,这种技术非常有用。软件中的一个常见工作是处理一个项目,它的目的是使用更新的实现替换旧系统。一个例子是用一个新的、热门的 Django 系统来替换旧的 COBOL 银行系统。动机通常是,通过使用比旧系统更容易使用的东西,来使其更容易维护和扩展。如果你可以编写一组自动测试来验证旧系统的行为,然后将该测试套件用于新系统,那么你可以通过一种方法,来确认你的替换品几乎正常。相信我,这些替代工作几乎是不可能的,通常不会成功,但自动测试是有帮助的。
这个练习中,你会向你的流程添加下面这些:
+ 在你需要实现的场景中,编写一个测试用例,运行原始的`hexdump`。让我们假设`-C`选项。你将需要使用`subprocess`启动它,或者简单地提前运行它,并将结果保存到加载的文件。
+ 通过测试你的`hexdump`版本,然后比较结果,编写使测试工作的代码。如果他们不等价,那么你就做错了。
+ 然后审计测试代码和你的代码。
我选择了`hexdump`,因为难度在于,复制其奇怪的输出格式来查看二进制数据。它的工作方式不是特别复杂。它只是匹配你需要的正确输出。这有助于你练习“测试优先”的测试。
> 注
> 当我说“先写一个测试”时,我的意思并不是一个庞大的`test.py`文件,它具有所有的函数和大量的虚构代码。我的意思是我以前教过的东西。编写一个小型测试用例 - 也许只是一个测试函数的1/10,然后编写代码使其正常工作,然后在两者之间来回跳动。你越了解代码,你就可以写出越多的测试用例,但不要写一堆测试代码,并没有东西来运行它。而是要逐步编写。
## 挑战练习
当你想要查看不是可见文本的文件内容时,`hexdump`命令很有用。它以各种有用的格式显示文件中的字节,包括十六进制,八进制,并且后面带有 ASCII 输出。实现自己的`hexdump`的难度不是读取数据,甚至不是将其转换为不同的格式。你可以使用 Python 中的`hex`,`oct`,`int`和`ord`函数轻松地执行此操作。原始的格式化字符串运算符也很有用,因为它为固定精度的八进制和十六进制格式化提供了选项。
真正的困难在于为每个不同的选项正确格式化输出,以便它能够正确流动并适合屏幕。以下是Python .pyc文件的hexdump -C输出的前几行:
真正的困难在于为每个不同的选项正确格式化输出,以便它能够正确打印并适合屏幕。以下是`Python .pyc`文件的`hexdump -C`输出的前几行:
```
00000000 03 f3 0d 0a f0 b5 69 57 63 00 00 00 00 00 00 00 |......iWc.......|
00000010 00 03 00 00 00 40 00 00 00 73 3a 00 00 00 64 00 |.....@...s:...d.|
00000020 00 64 01 00 6c 00 00 6d 01 00 5a 01 00 01 64 00 |.d..l..m..Z...d.|
00000030 00 64 02 00 6c 02 00 6d 03 00 5a 03 00 01 64 03 |.d..l..m..Z...d.|
00000040 00 65 01 00 66 01 00 64 04 00 84 00 00 83 00 00 |.e..f..d........|
```
这个“规范”格式化的手册页说:
+ 以十六进制显示输入偏移量。所以 10 不是十进制中的 10,它是十六进制。你知道十六进制吗?
+ 十六个空格分隔的,两列十六进制字节。这是转换为十六进制的每个字节。多少列代表一个字节?
+ 然后以`%_p`格式显示相同的十六个字节,看起来像 Python 格式化占位符,但它专用于`hexdump`。你需要阅读更多手册页,来了解其含义。
之后`hexdump`也可以从`stdin`输入接收输入,这意味着你可以将东西使用管道连接到它:
```
echo "Hello There" | hexdump -C
```
这会在我的 macOS 上产生如下输出:
```
00000000 48 65 6c 6c 6f 20 54 68 65 72 65 0a |Hello There.|
0000000c
```
请注意,最后一行有一个字符`c`?猜猜看这是什么。
这就是格式化和输出,它比较困难,你的任务是尽可能复制它,这就是为什么这个练习的开头让你以“测试优先”的方式工作。创建测试,将你的数据扔给`hexdump`将会更容易,并将其与真正的`hexdump`进行比较,直到它开始工作。
## 研究性学习
研究`od`命令,看看你的`hexdump`代码是否可以复用于`od`的实现。如果可以的话,可以制作一个他们都使用的库。
## 深入学习
有人主张只做“测试优先”的开发,但我相信没有永远适用的技术。当我从用户的角度测试软件的交互时,我更喜欢写测试。我将编写测试,它描述了用户与软件的交互,然后实现软件。这是你所做的事情,因为你正在测试,用户如何从你的`hexdump`命令行调用中看到输出。
对于其他类型的编程任务,决定首先写测试还是编写代码是荒谬的,只会扼杀你解决问题的能力。自动化测试是简单的工具,你是一个聪明的人,有权力尝试使用工具,但你认为他们将在每种情况下都能最好地工作。任何告诉你区别的人可能是一个无理取闹的人,实际上并不擅长编程。
- 笨办法学 Python · 续 中文版
- 引言
- 第一部分:预备知识
- 练习 0:起步
- 练习 1:流程
- 练习 2:创造力
- 练习 3:质量
- 第二部分:简单的黑魔法
- 练习 4:处理命令行参数
- 练习 5:cat
- 练习 6:find
- 练习 7:grep
- 练习 8:cut
- 练习 9:sed
- 练习 10:sort
- 练习 11:uniq
- 练习 12:复习
- 第三部分:数据结构
- 练习 13:单链表
- 练习 14:双链表
- 练习 15:栈和队列
- 练习 16:冒泡、快速和归并排序
- 练习 17:字典
- 练习 18:性能测量
- 练习 19:改善性能
- 练习 20:二叉搜索树
- 练习 21:二分搜索
- 练习 22:后缀数组
- 练习 23:三叉搜索树
- 练习 24:URL 快速路由
- 第四部分:进阶项目
- 练习 25:xargs
- 练习 26:hexdump
- 练习 27:tr
- 练习 28:sh
- 练习 29:diff和patch
- 第五部分:文本解析
- 练习 30:有限状态机
- 练习 31:正则表达式
- 练习 32:扫描器
- 练习 33:解析器
- 练习 34:分析器
- 练习 35:解释器
- 练习 36:简单的计算器
- 练习 37:小型 BASIC
- 第六部分:SQL 和对象关系映射
- 练习 38:SQL 简介
- 练习 39:SQL 创建
- 练习 40:SQL 读取
- 练习 41:SQL 更新
- 练习 42:SQL 删除
- 练习 43:SQL 管理
- 练习 44:使用 Python 的数据库 API
- 练习 45:创建 ORM
- 第七部分:大作业
- 练习 46:blog
- 练习 47:bc
- 练习 48:ed
- 练习 49:sed
- 练习 50:vi
- 练习 51:lessweb
- 练习 52:moreweb