Skip to content

Lec 0 设计程序指南 & 命令行工具

这部分有两大内容,一个是如何设计程序,一个是如何使用本课程的命令行工具。

1. 程序设计指南

1.1 引言

经验丰富的程序员通常能够在编写任何代码之前就构思出优雅的解决方案,而初学者则可能面临更大的困难。不必因此而灰心!重要的是要记住,这与天赋或能力几乎没有关系;这完全取决于经验,而且这是一种可以学习的技能(尽管需要大量的时间和练习!)

经验丰富的程序员之所以能够更快地找到正确、高效的解决方案,部分原因在于他们拥有更多“工具箱”;通过观察和解决更多问题,他们积累了更丰富的经验,可以从中汲取灵感。在本课程中,我们将尝试向您展示各种不同的问题(以及解决不同类型问题的具体技巧),以帮助您积累这些经验。

1.2 程序设计的通用框架

除了随着时间的推移积累的具体经验之外,在脑海中构思一个程序设计的通用框架也会很有帮助。 为了使这个过程尽可能顺畅高效,最好在心中形成一个计划之前,避免直接开始编写代码的冲动。经验告诉我们,面对新问题时,人们很容易立即开始编写代码,但花一点时间制定计划并设计解决方案,可以节省大量的时间,避免日后的痛苦。

有些人喜欢将这个过程形式化,有些人则不太喜欢,但思考这个过程的一种方法是将其分解为以下章节概述的四个步骤(灵感来自乔治·波利亚的精彩著作《如何解决它》(普林斯顿大学出版社,1945年),有人认为这是有史以来关于教学和解决问题的最佳著作)。

请注意,本大纲的很大一部分内容是关于将大问题分解成更小、更易于管理的部分(这些部分通常可以独立实现和测试)。 同样值得注意的是,遵循此流程并不一定能使为任何给定程序制定计划变得绝对简单,但我们希望它能让整个过程比原本更容易;并且随着时间的推移,这个过程将成为你的第二天性,但就目前而言,每次设计和实现程序时,仔细研究以下大纲仍然非常有帮助。

1.2.1 理解问题

设计程序解决问题的重要第一步是确保你真正理解你试图解决的问题。因此,一个好的起点是问自己以下问题:

  • 你想解决什么问题?
  • 输入是什么,输出是什么?我们如何在 Python 中表示它们?
  • 请列举一些输入/输出关系的示例?想出一些具体的小例子,以便稍后进行测试。

作为人类,你如何解决这些简单的情况?这些步骤具有普遍性吗?我们如何将其分解成足够小的步骤,以便计算机能够理解?

1.2.2 制定计划

一旦你对问题有了很好的理解,就该制定计划了,你可以问自己以下问题(事实上,在编写任何代码之前仔细思考这些问题是个好主意):

  • 寻找输入和输出之间的联系。需要执行哪些高级操作才能生成输出?如何使用这些操作构建输出?如何测试这些操作?
  • 除了输入之外,你还需要跟踪哪些信息?哪些类型的 Python 对象是表示这些信息的有效方式?
  • 你以前读过或写过相关的程序吗?如果是,该解决方案的某些部分可能会有所帮助。
  • 你能将问题分解成更简单的情况吗?如果您无法立即解决所提出的问题,请先尝试解决该问题的子部分,或一个相关但更简单的问题(有时是更一般或更具体的案例)。
  • 您的计划是否利用了所有输入?它是否产生了所有正确的输出?
  • 回想一下您对问题的理解,是否存在一些有趣的“边缘情况”需要考虑?您的计划是否考虑到了这些情况?

1.2.3 实施计划

只有在理解问题并制定计划之后,才有必要将计划转化为 Python 代码来付诸实践。在执行过程中,考虑以下几点会很有帮助:

  • 你可以将一些重要的高级操作实现为单独的“辅助”函数。
  • 在执行过程中,请参考此处概述的程序风格指南。如果您发现自己在重复计算,可能需要现在(而不是最后)重新组织。
  • 在执行过程中,请检查每个步骤和每个辅助函数:
    • 您能清楚地看出该步骤在一般意义上是正确的吗?
    • 您能证明它在一般意义上是正确的吗?
    • 该步骤是否通过了您之前的测试用例?
    • 您如何将该结果用作更大程序的一部分? 2.4

1.2.4 回顾

当您相当确定自己已经完成时,仍然值得退后一步,重新审视: 测试正确性和程序风格。 运行之前构建的每个测试用例,确保看到预期结果。

  • 还有其他测试用例需要考虑吗?
  • 你能否用不同的方法解决这个问题?如果可以,你选择的解决方案有哪些优缺点?
  • 你能用这个结果解决其他问题吗?你能用类似的编程结构解决其他问题吗?
  • 根据上一节讨论的规则,寻找改进代码风格的机会。 你的函数和变量名称是否简洁且具有描述性?
  • 你是否在某个地方重复了某个计算? 你的代码中是否有函数或其他片段可以推广?

1.3 组织和设计流程

即使遵循上述建议,如何组织流程也并非总是显而易见。并没有真正正确的答案,但许多人发现以下一项或多项措施会有所帮助:

  1. 在纸上以任何对你有用的格式勾勒出一个总体轮廓。这可能包括手工处理具体案例、概述有用的辅助函数、绘制图表、编写“伪代码”或任何其他对您有帮助的内容。

    通常情况下,当您路过经验丰富的程序员的办公室时,会发现他们办公室里写满了图表、代码大纲等的纸张(或白板或黑板)。

  2. 使用注释明确地编写大纲。尤其是在高层设计开始成形之后,甚至在编写任何实际代码之前,使用实际 Python 文件中的注释来整理思路会很有帮助。

    例如,您可以先编写一些空函数,除了详细说明其行为的文档字符串之外。然后,您可以在这些函数中编写注释,这些注释反映了您预期代码最终将采用的结构,概述了需要采取的高层步骤。这样,当真正需要实施计划时,您已经有了一个明确写出的高级计划,并且您可以考虑一次编写较小的代码片段,因为注释有望为您分解一些内容。

2. 命令行工具

虚拟化环境

pip -m venv myenv, then source myenv/bin/activate

pip freeze > requirements.txt

deactivate

静态检查工具

ruff

Rust写的工具,速度块

安装:pip install ruff

使用:

检查整个项目: ruff .

跳过某个检查: ruff --ignore E501

自动修复: ruff . -fix

pylint

pip install pylint

配置: pylint --generate-rcfile > .pylintrc 更改生成出来的配置文件

Pytest

常规用法 pytest test.py

显示详细信息:pytest -v test.py

第一个失败的测试用例停止执行:pytest -x test.py

即时打印print语句: pytes -s test.py

只运行名称中包含指定模式(如echo)的测试用例: pytest -k echo test.py

调试

python -i lab.py

在执行完后,不会退出,而是进入Python REPL, 可以访问Lab.py的所有定义。