1
0
mirror of https://github.com/apachecn/lmpythw-zh.git synced 2025-05-28 12:02:19 +00:00
lmpythw-zh/ex26.md
wizardforcel 9179831de0 ex26
2017-08-11 11:39:26 +08:00

75 lines
5.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 练习 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`命令行调用中看到输出。
对于其他类型的编程任务,决定首先写测试还是编写代码是荒谬的,只会扼杀你解决问题的能力。自动化测试是简单的工具,你是一个聪明的人,有权力尝试使用工具,但你认为他们将在每种情况下都能最好地工作。任何告诉你区别的人可能是一个无理取闹的人,实际上并不擅长编程。