前言
同学们是否听说过“编程”这个看起来很厉害的东西,但又不知道它到底是什么? 是否因为看到过电影里的黑客对着黑色的屏幕敲了一串字母最后酷眩地按下回车键,从而对计算机的世界感到好奇?
在本次实验中,我们将会用Python3这个编程语言为主来教会大家如何编写代码、如何运行代码,以及教大家如何像黑客一样对着你的电脑键盘一阵“乱敲”,然后按下回车键耍帅! 当然,我们还需要教会你一些不那么酷炫的事情——如何完成作业以及提交作业。
在开始之前,请先学习一下怎么浏览实验讲义。
- 点击左侧的目录可以直接跳转到对应的页面。
- 按下键盘上的右方向键,或点击页面右侧的箭头浏览下一页。
- 按下键盘上的左方向键,或点击页面左侧的箭头返回上一页。
学习指南
学会如何提问
大学生活和高中差别可大了,大家只有学会自己学习、学会向他人提问才能轻松掌握知识。 能够学会提问不仅能让大家更快解决你的问题,还能让大家更乐意帮助你。
在这里向大家推荐两个必读的传世经典:
助教希望大家能够做到:
- 首先尝试去独立解决问题;
- 尝试自己搜索问题的答案;
- 运用提问的智慧求助他人;
- 避免匿名提问、做伸手党。
遵守学术诚信
学术诚信是大学教学的重要部分,需要大家认真学习并严格遵守。
本课程鼓励大家通过QQ群提问等方式互相交流,但禁止包括但不限于下述的违反学术诚信的行为:
- 复制粘贴网上找来的代码
- 展示自己的代码给别人抄
- 直接提交别人的作业
- 在考试过程中作弊
根据《南京大学学士学位授予管理办法》,因违反学术诚信受到记过(含记过)以上处分者,不得授予学士学位。 学习并遵守学术诚信是一件非常严肃的事情,请大家务必认真对待。
环境配置
工欲善其事,必先利其器。
在本课程的实验中,我们用Python3这个编程语言来教大家编程。 我们想要用它进行编程,首先需要在自己的电脑上安装运行Python3的环境和编写代码的工具。
大家平时可能听得比较多的说法是Python,而不是Python3。 实际上,Python3表示Python这个语言的“3号版本”。聪明的同学可能想到,是不是Python还有其它版本?
没错,Python还有一个“2号版本”,叫做Python2。那还有Python1吗? 有是有,不过这是1991年发布的东西,现在可能已经见不到了。 Python3和Python2有很多不同的地方。但Python3比之Python2更加的新,也是被主流所使用的(Python2在2020年终止支持),因此我们的教学也采用了Python3。 在实验讲义和以后的课程中,如果我们没有明确说明,那么Python指的都是Python3。
本质上,代码就是一堆文本。那我们平时怎么编辑文本?当然是记事本、Word、在线文档!
所以,理论上我们使用Windows自带的记事本就可以写代码了。
你可以用记事本打开实验材料里的hello.py
试试(在Windows系统中,请右击文件,在“打开方式”中选择“记事本”,请勿直接双击文件)。
只要看到以下文本就说明没问题:
2022
print(2022)
我们把像Windows上这样的记事本软件称作编辑器(Editor)。 “原始”的程序猿们就是使用编辑器来编写代码的。 而“现代”的集成开发环境(Integrate Development Environment,简称IDE)就内置了一个足够好用的编辑器来给大家编辑代码。 对于本课程,同学们不需要过多了解IDE,只需要知道IDE集成了更多编辑器所没有的功能即可。
“原始”不代表真的原始。适合自己需求的才是最好的。
虽说现在我们知道了使用Windows自带的编辑器也可以写代码,但现实中真没有什么人这样干。 因为这个编辑器不是为我们写代码而设计的。 程序猿们开发了很多专门用来写代码的编辑器,VSCode就是目前最为流行的编辑器之一!
接下来,让我们来看看如何在自己的电脑上安装Python3和VSCode。
目前最主流操作系统有Windows系统、macOS系统和GNU/Linux系统。 考虑到同学们可能使用各种不同品牌的电脑与操作系统,本章节会兼顾这三种主流操作系统。
若在按照实验讲义操作的过程中有难以解决的问题,欢迎大家在实验课上或课程群中随时提问。
Windows
安装Python
在浏览器中访问https://www.python.org,点击下方的”Download“中的最新版本。
在新页面中直接翻到最底下,找到”Windows installer (64-bit)“,点击下载。
运行下载的安装程序,先勾选底部的“添加到PATH”,然后点击安装。
安装VSCode
在浏览器中访问https://code.visualstudio.com,点击下载按钮下载安装程序。
运行安装程序安装VSCode。
macOS
安装Python
macOS自带Python3。
安装VSCode
在浏览器中访问https://code.visualstudio.com,点击下载按钮。
你将会得到一个压缩包,将压缩包解压后出现一个VisualStudioCode.app
文件,将这个文件拖拽到访达(Finder)的“应用程序”中即可。
GNU/Linux
本节以Ubuntu 22.04为例,其他GNU/Linux操作系统请自行解决。
安装Python
Ubuntu自带Python3。
安装VSCode
在浏览器中访问https://code.visualstudio.com,点击下载按钮。
你将会得到一个.deb
文件,使用dpkg
安装该软件包。
$ sudo dpkg -i ./code_xxx.deb
小结
到现在,同学们应该已经完成了以下内容:
- 安装好了Python环境和VSCode编辑器。
VSCode基础
要学习如何编写程序,首先要知道如何使用编辑器和开发环境。 这些操作不仅在本课程中将被广泛用到,它还会伴随同学们完整的程序员生涯。
在本章中,我们将学习如何使用VSCode,并学习如何执行简单的命令。
认识VSCode
启动我们刚刚安装好的VSCode,你将会看到类似的界面(可能是黑色的,可能是英文的):
我们可以安装中文语言包。
点击左侧的“插件”选项卡,搜索“Chinese”,安装中文语言包,重启生效。
VSCode的界面由以下几个区域组成:
- 左侧的“主侧栏”
- 底部的“状态栏”
- 下方的“面板”
- 右侧的“辅助侧栏”
- 中间的编辑区域
点击右上角的按钮可以调整对应的区域是否显示。
点击菜单的 文件--打开文件,我们就可以打开一个文件进行编辑;点击菜单的 文件--打开文件夹,我们就可以浏览文件夹的内容并进行编辑。此时VSCode的界面主要包含:
- 左侧的“资源管理器”
- 资源管理器中的文件列表与文件大纲
- 中间的“文件编辑器”
- 下方面板中的“终端”
配置VSCode
相信同学们一定很好奇,上一节中助教的VSCode界面为什么和自己的不一样,怎么把VSCode配置的好看又好用,下面我们来教大家怎么配置VSCode。
拥有一个美观的编辑器能使编写代码的效率提升1000%。 建议大家花点时间钻研自己的编辑器配置。
配置文件
配置文件主要是设置VSCode的内部功能的。 点击菜单栏中的 文件--首选项--设置,或者按下键盘上的Ctrl+,(逗号,macOS用户为Command+,)组合键打开配置菜单。
我们建议大家立刻对VSCode的字体进行设置。
- 调整字体大小:
- 将VSCode的字体大小调整到合适的尺寸,建议使用14、16等稍微大一点的字号
- 在设置中搜索"font size",终端、调试器的字体大小也需要修改
- 调整字体系列:
- VSCode默认使用等宽字体,但是大家可以下载更好看的字体替换
- Jetbrains Mono https://www.jetbrains.com/lp/mono/
- Cascadia Code https://github.com/microsoft/cascadia-code
- VSCode默认使用等宽字体,但是大家可以下载更好看的字体替换
Jetbrains Mono 和 Jetbrains Mono NL 有什么区别?
Jetbrains Mono字体中,
==
、!=
、>=
等符号会用连字符表示(有点类似于手写体),可能和大家编程的习惯不太匹配,建议大家优先选择 Jetbrains Mono NL。
自动保存
就如同大家写word文档时需要保存一样,在VSCode写代码时也需要及时保存。
当你看到下图中被红框框起来的白点时,代表这个文件被修改但没被保存。
保存文件的重要性我想不必多说(往年经常遇到因为忘记保存文件而产生的奇怪bug),因此请各位在写代码时及时地使用快捷键【Ctrl+S】来保存文件,尤其是当你写完一段代码打算测试或者提交时,一定要先保存文件再测试或提交。
当然,你可能会说每次都要自己手动保存又麻烦还容易忘,有没有办法解决这个问题呢?答案是肯定的!我强烈建议各位启用VSCode的自动保存机制。
还是在刚刚的设置界面,第一项就是【自动保存】选项,这里我个人建议选择【onFocusChange】,这样的话只要鼠标点到编辑区域外面,就会自动保存正在编辑的文件,很方便!
安装插件
和刚才安装的中文语言包类似,VSCode的很多额外功能都是通过插件的方法来实现的。
我们建议大家仅安装自己所需要的功能,避免VSCode变得太臃肿。
下面是一些助教常用的插件:
- Python:Python开发套件,默认已经安装。
- Ayu:助教使用的白色主题,有Light/Mirage/Dark三种颜色、两种对比度,共六种风格可选。
- Reload:在状态栏右侧提供一个重载按钮,点击即可重载VSCode(VSCode工作不正常时点一下)
- EditorConfig for VS Code:使用
.editorconfig
来配置编辑器行为。 - Prettier - Code formatter:使用
prettier
进行代码格式化。
终端(Terminal)
什么是终端?
我们知道,要让计算机执行计算,必须将指令和数据输入到计算机当中。
早期的计算机并没有鼠标、显示器等“高科技”产物,程序员需要将数据标记在卡片或磁带上,或者是是用电传打字机(teletype)输入进计算机进行计算。 上面的图片展示的设备叫做VT100,是一种具有显示器的终端,能够将使用者的输入传输进计算机、显示计算机的输出、并支持光标控制等多项任务。 当拥有图形界面的操作系统(如Windows)开始流行后,显示器被好看的图形界面所占用,终端则是以硬件模拟器(terminal emulator)的方式继续存在,如今大家使用的终端大多是在模拟VT100。
既然终端是一种硬件,我们在终端里究竟是和谁在交互?
操作系统为用户提供了一个“交互界面”,这个程序(软件)叫做壳层(shell)。在Windows中,图形用户界面由
explorer.exe
提供,命令行界面由powershell.exe
或cmd.exe
提供。在Unix系统中,命令行界面有sh
、bash
、zsh
、fish
等多种实现。未来我们提及终端的时候,更多指的是终端模拟器外加上操作系统壳层程序所组成的整体。
打开终端
点击菜单栏中的 终端--新建终端,或者按下Ctrl+Shift+`(ESC下面的键),或者在面板中点击加号打开一个新的终端。 VSCode的面板中可以左右分屏或创建多个终端,大家可以自己试试。
认识终端
我们首先来理解一下终端上显示的到底是什么,再来学习如何让终端执行我们的“命令”。
以Windows为例,当你打开终端后,你可能会看到终端上显示着类似于下面这样的文字(取决于大家Windows的版本,显示的实际内容可能会略有出入):
Windows PowerShell
版权所有(C) Microsoft Corporation。保留所有权利。
安装最新的 PowerShell,了解新功能和改进!https://aka.ms/PSWindows
PS D:\sicp\lab00>
首先前面几行是关于微软的一些信息,我们不用管它。终端的最下面一行显示了这样一段文字:
PS D:\sicp\lab00>
我们把这串字符称为“提示符”(Prompt),它本身代表了一些当前系统的信息,并“提示”你,终端正在待命,你可以在光标处输入命令! 那这串提示符的信息该怎么理解?我们可以把它分解为以下几个部分:
- 第一部分是
PS
,表示当前终端使用的是Powershell,不同的终端可能会展示不同的内容。 - 第二部分是
D:\sicp\lab00
,表示终端的“当前工作目录”。这个概念我们会在后面“文件查找与当前工作目录的切换”的部分会详细讲解。 - 第三部分是
>
,提醒你可以在它后面输入命令了。
终端中的提示符的格式是可以自定义的。每个平台都可能有不同的格式。所以我们再以macOS为例,看看助教的笔记本终端长什么样。
可以看到,第一行仍然是操作系统相关的信息,但是提示符比较花哨,显示了三个部分:
- 第一行左侧蓝色的
~
,表示当前的工作目录。 - 第一行右侧淡蓝色的当前时间。
- 第二行左侧绿色的
>
,表示可以在后面输入命令。
~
是什么?部分壳层程序提供波浪号扩展(Tilde Expansion)的功能,
~
将被展开成环境变量$HOME
,也就是用户的“家目录”,类似于Windows的C:\User\YOURNAME
。
我也用的macOS,为什么我的和助教的不一样?
macOS中的默认的提示符是
$
。 感兴趣的话,你可以抄助教的终端配方:
- Oh My Zsh https://ohmyz.sh
- Powerlevel10k https://github.com/romkatv/powerlevel10k
执行命令
现在,大家应该理解了“提示符”的含义。接下来我们就可以试试在终端上输入命令执行了。
我们首先输入一个简单的命令来看看Python是否安装成功!
如下图所示,请大家向终端敲入命令:python3 --version
,然后按下回车键。
使用Windows的同学:为什么我按下回车什么都不显示,或者是运行
python3
弹出了应用商店?Windows和其他的操作系统有所不同,Windows下的安装的Python3程序叫做
python
,其他操作系统叫做python3
,我们需要给python
设置一个别名来消除不同操作系统之间的差别。如果我们不进行这一步,我们在执行
python3
时会运行Windows提供的一个缺省程序,跳转到应用商店安装Python3。对于使用Windows的同学,我们建议大家正确配置别名,使得输入python3
也能执行Python3,而不是打开Windows应用商店。
首先,在终端中执行以下指令:
Set-ExecutionPolicy -Scope CurrentUser RemoteSigned
这个指令的意思是,将当前用户的脚本执行策略设置为
RemoteSigned
,允许执行本地创建的脚本,以及从网络上下载下来且具有数字签名的脚本。 执行指令后,终端不会有任何输出。接着,我们打开文件资源管理器,在“文档”文件夹下新建一个叫做
WindowsPowerShell
(注意大小写)的文件夹,并创建一个叫做Profile.ps1
的文件。用VSCode打开
Profile.ps1
,写入以下内容并保存:Set-Alias -Name python3 -Value python
很显然,这个指令的意思是,将
python3
设置为python
的别名。 别名只在当前终端会话中有效,因此我们要把它写入Profile.ps1
,使得你每次启动终端都自动设置别名。如果你的操作正确,此时开启一个新的终端,运行
python3 --version
将打印Python版本。
可以看到,终端(实际上是操作系统)执行了我们输入命令,并把结果"Python 3.10.7"输出到了终端中——这代表助教所安装的Python的版本是3.10.7。 大家看到的结果不必和助教这边显示的完全相同,只需要看到输出了你安装的Python版本号即可。
大家还可以看到,终端又在最下方输出了一行提示符,提示大家可以输入新的命令了!
到这里,大家已经用终端执行了第一个非常简单的指令。
在以后的课程讲义和各类沟通交流中,我们应当避免使用图片来显示命令的运行结果,倾向于使用文本的方式来进行展示。
根据习惯,我们使用$
这一简短的符号来代替原本图片中一长串的提示符。未来大家会在网络上看到更多这样的表达。但是请大家注意,提示符是交互程序打印在终端上给你看的,在输入其他人给的命令时,不要把提示符也敲进去!
比如,查看Python版本号的例子可以用下面的文本进行描述:
$ python3 --version
Python 3.10.7
小结
到现在,同学们应该已经完成了以下内容:
- 安装好了Python环境和VSCode编辑器。
- 掌握了使用VSCode来:
- 打开文件或目录
- 打开终端并执行指令
掌握一些关于终端和脚本的知识吧!
相信你一定很想了解终端的各种用法,想要成为一名炫酷的“黑客”。
然而,很可惜,关于终端的大部分知识在课堂上都学不到,需要你自己去动手实践掌握。 大家并不会去刻意学习如何使用终端,一不小心“删库跑路”的时候才会后悔当初没有认真掌握终端如何使用。
助教强烈推荐大家课后观看The Missing Semester of Your CS Education的前两节课程(大约一个半小时),跟着视频一起了解终端的基础用法。
Python基础
我们已经了解了如何打开终端并执行命令。接下来,我们就可以正式开始学习Python了!
抽象地来讲,Python代码主要由表达式(Expression)和语句(Statement)组成。 而为了执行程序员编写的Python代码,有一个叫Python解释器(Python Interpreter)的软件来负责一行一行地读取Python代码来执行。
一方面,我们能把Python代码都写在文件中,让Python解释器从文件中读取代码执行。 另一方面,Python解释器有一个“交互模式”,能支持我们以交互的方式在终端上一行一行地向Python解释器输入Python代码,来即时地查看相应的执行结果。 如果你把某个Python文件中的代码复制到Python解释器的交互模式中执行,那么得到的结果应该是和解释器直接执行这个Python文件的结果是一致的!
在本章中,我们首先讲解Python解释器的“交互模式”,然后在交互模式中给大家展示Python代码(即表达式和语句)的执行结果。 最后,我们教大家在文件中编写Python代码,并使用Python解释器执行它。
Python解释器
刚才我们说过,Python解释器是用来执行Python代码的软件。 Python解释器除了能读取文件中的代码执行,也支持在终端上读取我们输入的表达式和语句执行并展示结果——这很方便大家学习Python。 我们来看看如何启动Python解释器的“交互模式”。
在打开的终端中,我们可以直接用键盘输入python3
这个命令,然后按一下回车键启动Python解释器的交互模式界面。效果如下所示:
$ python3
Python 3.10.7 (tags/v3.10.7:6cc6b13, Sep 5 2022, 14:08:36) [MSC v.1933 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>>
大家很可能看不懂执行python3
命令后终端所显示的内容。不过不用慌,我们带大家分析一下上面的每串字符。首先是第一和第二行:
Python 3.10.7 (tags/v3.10.7:6cc6b13, Sep 5 2022, 14:08:36) [MSC v.1933 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
这是Python解释器开始运行交互模式后打印的一些信息,比如第一行打头的“Python 3.10.7”这个版本号。 我们不必在意。大家终端上显示的信息不必和这里展示的信息完全一致,但版本号必须是3.x.y的形式。
还记得我们之前通过
python3 --version
来查看Python版本号吗?
接着,Python解释器在第四行显示了>>>
这个符号。这个符号也是提示符,只不过和我们刚才见过的长得有点不一样。
它代表了我们可以输入一些“东西”跟Python交互了。对于终端来说,大家能在终端的提示符后面输入命令来让终端(操作系统)执行;
而对于Python解释器来说,大家能在提示符>>>
后面输入表达式与语句来让Python解释器帮你做计算。
举一个例子,我们现在可以在提示符>>>
后面输入1 + 1
,按下回车键,看看Python会不会计算这个小学生都会算的事情。结果如下:
>>> 1 + 1
2
可以看到,Python解释器很灵性地计算了1 + 1
,得到2
,并把2
输出给你看,然后很积极地再打出了提示符>>>
,提醒你输入下一个表达式或语句来让它计算。
概言之,交互模式便是一种“你输入表达式或语句,Python解释器执行它,你再输入表达式或语句,Python解释器再执行它……”的重复过程,
直到你不想再和Python解释器说话,敲入exit()
为止(见3.3节),交互模式就结束了。
在本小节的最后,让我们来比较一下和Python解释器交互以及和终端交互时两者提示符的区别吧。
和Python交互时的提示符是>>>
,而和终端交互的提示符是>
(在Linux和macOS则通常是$
)并且在前面往往有表示“当前工作目录”的文字。
大家要注意区分这两种模式——既不能在和Python交互时输入只有终端才能懂的命令,比如python3 hello.py
,
也不能在和终端交互时输入只有Python解释器才能懂的表达式或语句,比如1 + 1
。
表达式与语句
接下来,我们来正式学习一下表达式和语句的概念,并在Python解释器的交互模式中来检查它们的执行结果。
大家在高中阶段一定见过8 * 8
, a + b
, 7 - (x + y)
之类的数学表达式,
而程序表达式也是类似的,它们由数字(亦称为常数)、变量(如a
, x
等,用字母表示)、运算符(如加法、乘法符号等)等组成,
一些表达式还包含了函数,这在课上会讲到(不妨试着用数学里的“函数”概念去理解它)。
我们知道,如果表达式里面每个部分的值都是已知的(例如,a + b
中a
的值为4、b
的值为5),那么整个表达式就可以被求值。
让我们来看看Python里面的表达式和求值是什么样的。
1. 基本表达式
基本表达式(Primitive Expressions)只需要一步便可以求得它的值,例如整数、浮点数和布尔值:
>>> 3
3
>>> 12.5
12.5
>>> True
True
同学们可以像上面这样在交互模式下输入表达式,并按回车键查看结果。
浮点数是一种带小数点的数。之所以叫它浮点数,是因为它和计算机底层的表示有关。等大家上《计算机系统基础》这门课的时候就会理解了。
变量名同样也是基本表达式,求值的结果为在当前程序的状态下绑定到的值(更多内容见赋值语句)。
2. 布尔值与布尔表达式
布尔值只有两种值,True
和False
,表示逻辑上的“真”与“假”。
例如,我们知道数字1是不等于2的,所以若在Python交互模式中输入1 == 2
(这个表达式意思是“1等于2”,在Python中一般用==
表示“相等”),
则会得到它的值为False
;相反,如果输入1 != 2
(表示”1不等于2“,在Python中一般用!=
表示”不相等“),则会得到值True
。
这种能计算出布尔值的表达式我们称之为布尔表达式(Boolean Expression)。
>>> 1 == 2
False
>>> 1 != 2
True
3. 算术表达式
可以通过对数字和数学运算符的组合产生复杂的算术表达式(Arithmetic Expression)。
Python中常见的数学运算有+
(加)、-
(减)、*
(乘)、**
(乘方)和以下三种:
- 浮点除法 (
/
):计算第一个数除以第二个数的结果,得到一个浮点数(即使能够整除)。 - 下取整除法 (
//
):计算第一个数除以第二个数的下取整后的结果,得到一个整数。 - 取模 (
%
):计算第一个数除以第二个数的余数(>0), 得到一个整数。
>>> 1 + 2
3
>>> 3 - 2
1
>>> 5 * 6
30
>>> 7 / 4
1.75
>>> 7 // 4
1
>>> 7 % 4
3
>>> 4**3
64
像大家平时学过的数学运算一样,算数操作也有优先级,比如乘方运算的优先级大于乘除运算,乘除运算的优先级大于加减运算。 同样地,你也可以通过“加括号”来改变求值优先级。注意,优先级不需要记忆。当你对运算优先级拿不准的时候,就多加括号!
>>> 2 + 6 / 4
3.5
>>> (2 + 6) / 4
2.0
4. 赋值语句
一个赋值语句(Assignment Statement)由一个变量名和一个表达式组成。它会在当前帧(帧的概念后续课程会讲)下把变量名与该表达式的值绑定。
>>> a = (100 + 50) // 2
注意:在Python中,不能对语句进行求值。
你可以输入一个之前定义过的变量名,例如a,Python解释器会输出其绑定到的值。如果你还记得之前的内容,a
也是一个基本表达式:
>>> a
75
注意这里a
被绑定到75
, 而非(100 + 50) // 2
—— 变量名绑定到值而非表达式上。
5. print
print()
是Python3的内置函数,它可以将一个表达式的值输出到终端上(如果还不清楚函数的概念,就单纯记忆一下它的用法吧)。
print(2022)
也是一条语句:
>>> 2022
2022
>>> print(2022)
2022
注意,上面在交互模式下输入2022
和print(2022)
显示的结果看上去相同,但前者是交互模式下自动输出的每一行表达式的值,
后者是print()
在终端中的输出。在非交互模式下(即执行Python代码时,后面会讲),如果你想知道结果,请用print()
。
退出交互
当你完成与Python的交互后,可以进行以下操作来退出交互:
- 输入
exit()
或者quit()
并回车 - 在Windows下,按下
Ctrl+Z
并回车 - 在macOS和Linux下,按下
Ctrl+D
可以看到,你的终端不再显示Python的提示符,而是显示了自己的提示符。 这说明你又可以向终端(而不是向Python交互界面)输入新的命令了。
执行Python文件
大家已经知道,Python代码是由表达式和语句组成的。而现在大家已经学会了一些简单的表达式和语句,并在交互模式下体验了执行它们的效果。 现在,我们就可以把之前学过的表达式和语句都写入到文件中,然后让Python解释器直接从文件中读取它们并执行。
关于编写代码,我们已经事先准备了一个编写好的文件hello.py
(约定俗成,大家以.py
的后缀来表示这是一个Python代码文件)。
这个文件中有下面内容:
2022
print(2022)
你也可以利用任何任何文本编辑器修改hello.py
,尝试前面提到的其它表达式和语句,或者试一试其它你感兴趣的内容。
接下来,你需要打开终端,然后输入python3 文件名
命令来执行这个Python代码文件。在这里,你需要输入:
$ python3 hello.py
然后可以得到结果:
2022
有时你可能会发现执行Python文件报出了错误
[Errno 2] No such file or directory.
,遇到这种情况请继续往下看下一小节。
另外,你可能还会疑惑为什么只显示了一个
2022
。现在你需要回顾一下前面3.2.5小节的内容。你会发现,原来
2022
这种表达式仅会在交互模式下显示求值结果。这里不是交互模式,所以表达式2022
没有显示任何结果。 屏幕上的2022
是由print函数“打印”出来的(难怪它叫
文件查找与当前工作目录的切换
在执行python3 hello.py
时,大家有可能会看到终端上显示出错误:
$ python3 hello.py
python: can't open file 'hello.py': [Errno 2] No such file or directory.
这和Python解释器的文件查找机制有关。
大家还记得先前提到的“当前工作目录”的概念吗。不记得了可以跳回2.3节去看一眼:终端会在提示符里面显示当前的工作目录。
而当你键入python3 hello.py
时,Python解释器会在当前的工作目录里去找hello.py
并执行。
而如果你当前工作目录下没有hello.py
文件时,Python解释器就会报错了。
假设你有一个文件夹叫做D:\SICP
,并且你把我们下发的实验材料的压缩包解压在了这个文件夹中,也就是说你的实验材料都在D:\SICP\lab00
下。
如果我们用VSCode打开文件夹D:\SICP
,我们在VSCode中打开终端时当前工作目录会被设置为是D:\SICP
,在当前的目录下并没有hello.py
这个文件。
此时你知道hello.py
在D:\SICP\lab00
目录下,那么当你执行:
D:\SICP> python3 hello.py
就会出现问题。但如果你当前的工作目录是D:\SICP\lab00
,那么你执行:
D:\SICP\lab00> python3 hello.py
就不会有任何问题。那么接下来你就会问,该如何改变当前的工作目录呢?你可以通过cd
这个命令切换终端的当前工作目录!
cd
的全称是change directory。
一方面,你可以通过cd
后跟一个目录的“绝对路径”来把工作目录切换成“绝对路径”所表示的目录。
比如在上面的例子中,如果你当前的工作目录是C:\User\Dell
,那么你可以像下面这样切换当前的工作目录到D:\SICP\lab00
:
C:\User\Dell> D: # 注意,不能通过cd切换盘符
D:\> cd D:\SICP\lab00
D:\SICP\lab00> python3 hello.py
什么是绝对路径?像
D:\SICP\lab00
以盘符(C盘的盘符叫做C:
,D盘的盘符叫做D:
,以此类推)开头的路径,就叫做绝对路径。否则叫相对路径。在macOS和Linux中并不存在“盘符”的概念,在这些操作系统中,最底层的文件夹叫做“根目录”(
/
,也就是“root”),以/
开头的路径叫做绝对路径,如/home/user/sicp/lab00
。你可能会注意到,Windows上路径的目录之间使用
\
分割,而macOS和Linux则使用/
分割。
另一方面,你也可以通过cd
后跟一个目录的“相对路径”来把工作目录切换成“相对路径”所表示的目录。
比如,如果你当前的工作目录为D:\SICP
,并且这个目录下还有一个lab00
目录,那么你可以像这改变当前的工作目录:
D:\SICP> cd lab00
D:\SICP\lab00>
这里的lab00
就是相对路径。这个过程就很像你在资源管理器的SICP
目录下双击了lab00
目录,然后就进入了lab00
目录一样。
如果你的硬盘上不存在目标目录,那么执行cd
指令就会显示错误。你可能需要打开资源管理器看看是怎么回事。
如何回到上一级目录中?
在表示目录时,
..
的含义为上一级目录。.
的含义为当前目录。可以使用cd a\b\c
这样的形式一口气进入多层目录(a\b\c
就是所谓的相对路径)。C:\SICP\lab00\code> cd .. # 进入上层目录 C:\SICP\lab00> cd .. # 再次进入上层目录 C:\SICP> cd lab00\code # 进入lab00目录下的code目录 C:\SICP\lab00\code> cd ..\.. # 进入上层目录的上层目录 C:\SICP> cd .\lab00 # 进入当前目录的lab00目录 C:\SICP\lab00> cd ..\lab00 # 进入上层目录的lab00目录 (即还是当前目录) C:\SICP\lab00>
怎么查看当前工作目录下的有哪些目录与文件?
你可以通过
ls
命令或dir
命令(仅Windows)显示当前目录下的文件。PS D:\sicp\lab00> ls 目录: D:\sicp\lab00 Mode LastWriteTime Length Name ---- ------------- ------ ---- -a---- 2022/9/17 12:04 47 .editorconfig -a---- 2022/9/17 0:26 23 .gitignore -a---- 2022/9/17 0:26 19 hello.py -a---- 2022/9/17 0:26 383 lab00.ok -a---- 2022/9/17 0:26 570 lab00.py
小结
到现在,同学们应该已经完成了以下内容:
- 安装好了Python环境和VSCode编辑器。
- 掌握了使用VSCode来:
- 打开文件或目录
- 打开终端并执行指令
- 掌握了如何在终端下执行命令:
- 使用
cd
命令来切换终端的当前工作目录。 - 使用
python3
相关的命令来:- 进入Python解释器的交互模式,执行简单的表达式和语句,以及退出交互;
- 启动Python解释器来执行
.py
代码文件。
- 使用
如何完成实验
现在,大家应该熟悉了如何用Python编写代码以及运行代码的过程。那接下来,我们就要讲解大家可能最不愿意看到的东西了——如何完成实验?
在我们的课程实验中,大家需要补充作业文件中的函数定义来完成一些题目(暂时不知道函数是什么也没关系)。不要担心,我们首先带大家一起完成一道题目来熟悉这个流程。
作业文件
首先从课程主页或群文件里下载本次实验所需的文件,对于本次实验是lab00-Code.zip
这个压缩包。
首先,新建一个文件夹,再将lab00-Code.zip
中的文件解压到这个文件夹。之后每次作业都需要如此解压到一个新文件夹再开始写,切忌直接双击打开压缩包中的文件或者直接解压到旧作业的文件夹中!!!
对第一次接触电脑的同学:解压软件我个人推荐7-Zip。解压方法是点击左上角的【提取】,然后选择刚刚新建的文件夹;或者全选(用鼠标框住或使用快捷键【Ctrl+A】)压缩包中所有文件,再用鼠标拖到刚刚新建的文件夹中。
然后打开刚刚解压到的文件夹,右键点击一处空白区域,再选择【用Code打开】。这样操作相当于用VSCode打开整个文件夹,这对后面的实验会比较方便。我个人不建议通过双击lab00.py
来用VSCode打开单个文件的方法。
本次实验的作业文件是lab00.py
。
打开lab00.py
,首先能看到下面这段代码:
def twenty_twenty_two():
"""Come up with the most creative expression that evaluates to 2022,
using only numbers and the +, *, and - operators.
>>> twenty_twenty_two()
2022
"""
return ______
上面代码里包含了我们将要完成的第一个题目——2022(这个题目就叫做2022)。看到上面的代码时,你可能是一脸懵逼的。不过不要慌,我们来一步一步理解。
首先,这段代码使用def twenty_twenty_two()
定义了一个函数twenty_twenty_two()
。如果在实验课前老师还没讲如何定义函数,大家也不用着急。不知道这个知识点也能完成本次实验。不过,在下一次课上你应该就会学到如何定义函数了。
接下来,我们会看到一段被三引号"""
包围的文本。我们把这段文本叫做docstring(全称document string,即文档字符串)。它一般被用来描述一个函数应该做什么。在我们twenty_twenty_two
的例子中,这段docstring告诉我们:“写出一个富有创造力的表达式,使得计算它的值能得到2022”(当然,在本次实验中没那么有创造力也无妨)。此外,它还要求我们只可以使用数字和加减乘除。
紧接着,我们能看到有一行docstring是以>>>
开头的。从这行开始往下的docstring被叫做doctest (举一反三一下,它的全称为什么?——document test)。回想一下大家在前面使用的Python交互模式,>>>
被我们称为提示符——它告诉我们可以在它后面输入表达式或者语句。是不是当你在>>>
后面输入一个表达式后,Python解释器就会在下一行打印这个表达式的值?doctest就是通过这样的示例来告诉你一个函数会做什么:“当我们在交互模式下这样输入代码,就会得到这样的结果”。在我们twenty_twenty_two
的例子中,doctest告诉我们:“当我们在交互模式下输入twenty_twenty_two()
,就会得到2022”。
总的来说,docstring和doctest分别使用“描述”和“举例”的手段来告诉我们一个函数的行为。未来在大家完成实验题目的时候,除了阅读实验讲义,也最好读一读它们加深自己的理解。
写点代码
现在,我们应该理解了作业文件中的第一个题目,即写一个(有创造力的)表达式,使得它的值为2022
。
那么我们该把这个表达式写在哪里呢?我们的实验讲义会把这种要求都描述清楚。本次实验其它题目的描述可以在左侧的“本次实验内容”一节中找到。作为一个带大家一起做的例子,我们现在先告诉大家第一个题目的要求:请用你想到的那个表达式替换掉twenty_twenty_two
中下划线的部分。
当然,我们之前说过第一个题目我们会带大家一起做。所以虽然不知道富有创造力的大家想到了什么表达式,但没有创造力的助教们就想了一个这样的答案:
def twenty_twenty_two():
"""Come up with the most creative expression that evaluates to 2022,
using only numbers and the +, *, and - operators.
>>> twenty_twenty_two()
2022
"""
return 2021 + 1
大家可以修改各自得到的lab00.py
文件,把下划线替换成自己想到的表达式。
我实现的对不对?
现在,大家已经完成了第一个题目。这个题目当然是很简单的,但之后随着知识的增多,我们要完成的题目也越发复杂。那么有没有什么方法能检验我们写的代码对不对呢?
手动测试我的代码
回想一下,doctest描述了“当我们在交互模式下这样输入代码,就会得到这样的结果”,那么我们是不是可以打开交互模式,按照doctest的描述输入代码,然后观察结果是不是一致的呢?
答案是肯定的。我们在VSCode中打开终端,执行python3 -i lab00.py
。
这个命令长得和我们在前面学过的
python3 lab00.py
很像,但多了个-i
。-i
是告诉Python,在使用python3 lab00.py
执行完lab00.py
后,进入交互模式。而开发Python的程序员之所以采用i
这个字母,是因为它是interactive的首字母,方便记忆。
你应该能在终端上看到下面的效果:
$ python3 -i lab00.py
>>>
接下来的过程就和交互模式一模一样了。你可以对照着doctest,输入twenty_twenty_two()
,然后就会得到:
$ python3 -i lab00.py
>>> twenty_twenty_two()
2022
>>>
这和doctest描述的一模一样,所以你现在可以松口气,相信自己的代码是对的了。如果发现不一样,你就需要看看自己哪里出问题了。
等一等!刚才其实有一个概念的陷阱。现在让我们思考一个问题:为什么说,经过刚才这样一个过程,我们就有理由相信我们的代码是对的呢?
实际上,“相信自己的代码是对的”是一个错误的说法!准确的说,大家只能有理由相信“自己写的代码和doctest所预期的相符合”,进而推论,自己的代码可能是对的。
其实,像这样一个比较代码的实际执行结果和预期结果的过程就叫做测试。这也是“doctest”中test的中文含义。测试不能保证“代码是对的”,只能保证代码在多大程度上与预期相符合。与预期符合得程度越高,我们就更加有信心来相信,我们的代码是对的。
实际上,还有一种检查程序正确的方式叫做形式化验证(Formal Verification),通过规则和逻辑(而非测试样本)来判断程序的正确性。这正是冯新宇老师研究的领域之一。在你之后的学习过程中可能还会进一步接触相关内容。
使用Ok进行自动化测试
随着大家做的题目越来越多、越来越复杂,同学们可能会发现,每当自己写了一段新的代码,就要重新走上面一套doctest的流程,然后嫌手动输入表达式很麻烦。
我们可以使用随作业下发的Ok客户端来进行自动化测试。
运行python3 ok
,Ok会和上面的代码一样执行所有的doctest或其他配置好的复杂测试,并在第一次出错时停止执行。
如果我们使用-i
参数,如python3 ok -i
,那么出错时就会进入交互模式,方便我们进行排查。
为什么我运行
python3 ok
打开了浏览器,访问了南京大学代码托管系统?Ok不仅是一个测试工具,我们还需要用它提交作业。 在下一节中我们会介绍怎么注册系统并提交作业,现在不需要管。 直接关闭浏览器的页面,在终端中按下
Ctrl+C
组合键即可退出Ok。
$ python3 ok
=====================================================================
Assignment: lab00
OK, version 2022.09.16
=====================================================================
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Running tests
---------------------------------------------------------------------
Doctests for twenty_twenty_two
>>> from lab00 import *
>>> twenty_twenty_two()
# Error: expected
# 2022
# but got
---------------------------------------------------------------------
Test summary
0 test cases passed before encountering first failed test case
助教会如何测试我的代码?
对于助教来说,很难一一审查每个人的代码来验证大家写得正不正确,所以我们会采用测试的方法来给大家评分。像我们发布给同学的doctest一般都写得比较简单,所以那些写得不正确的代码也有可能通过doctest,比如像下面这段代码,本来助教希望大家写return a + b
,但有个小机灵鬼直接返回3试图蒙混过关:
def add(a, b):
"""return the sum of a and b
>>> add(1, 2)
3
"""
return 3
但如果我们的测试写得越“详细”,写得不正确的代码就越难蒙混过关。
def add(a, b):
"""return the sum of a and b
>>> add(1, 2)
3
>>> add(3, 4)
7
"""
return 3
因此,助教们会设置一个在线测评网站,用更加“详细”的、对大家隐藏起来的测试来给大家评分,尽可能防止不正确的代码蒙混过关。我们会在下一节中教大家如何提交作业,让助教测试你的代码。
本节关于测试的介绍,如果大家理解得不清楚也没关系。重点是记住下一节要讲的提交作业的方法,并知道如何查看自己写的代码拿了多少分。
提交作业与评分
为了获取分数,我们需要使用随作业下发的Ok客户端进行测试并提交。 这里助教特别强调,所有作业都必须使用Ok进行测试并提交,作业系统不再提供直接上传文件的提交功能。
使用Ok是保护作业文件、遵守学术诚信的有效手段。 UC Berkeley开发的Ok是一个对作业进行测试、备份、提交的程序。 助教在2021年的时候把Ok进行了魔改,支持了我们自己的作业系统。
当你用Ok对自己的代码进行测试时,Ok会把你的代码备份到作业系统。 如果你一不小心手滑把电脑砸了/掰成两半了/泡水里了1/格式化了,可以向助教索要最新的备份文件,或自行在作业系统上下载已经提交的代码。 同时,大家完成作业产生的一系列备份文件,可以用于调查是否存在违反学术诚信的行为,也可以帮助自己证明自己是独立完成作业的。 从2021年收集到的数据来看,很多同学完成困难的作业题需要尝试十几次才能获得满分。
我们考虑这样的一个例子:同学A的在布置作业后一直没有任何尝试,在截止日期当晚直接满分,助教都认为困难的题目没有任何尝试就做对了,且复杂的代码与同学B的高度相似。 在没有能够证明A自己独立完成作业的可信证据的情况下,其行为将被认定为抄袭。 作业抄袭或其他学术不端行为初犯将取消作业成绩(两人的成绩都为0),再犯则课程成绩按0分计并提交到本科生院。
1:真实的事件,某位2019级拔尖班学长喝饮料的时候把饮料浇到了电脑上。
系统注册
为了能够提交作业并获得评分,同学们需要完成下面的事情:
- 在南京大学电子邮件系统开通自己的学生邮箱,如何开通请看【IT服务】南大邮箱系列问答。
- 在南京大学代码托管系统使用自己的学生邮箱注册一个账号。
- 第一次登录本课程作业系统必须使用学号邮箱,不能是自定义的邮箱地址。
- 如果你已经用其他邮箱注册过代码托管系统,可以在用户设置页面修改自己的邮箱。
- 点击填写SICP2022作业系统注册&小调查,填写完成后过几秒钟就可以登录作业系统了。
你可能会问,为什么不用用户名密码登录的方式?
- 助教不想管理密码。
- 很多同学一直都用默认密码不修改2。
- 代码托管系统提供了重置密码、2FA等功能。
2:真实的事件,不改密码的话,别人可以登录你的账户下载你的作业。
提交作业
在第一次运行Ok完成测试时,Ok会提示我们进行身份验证。
如果我们需要重新登陆或者退出当前的用户,可以在终端中执行python3 ok --authenticate
,在浏览器中完成身份验证。
$ python3 ok --authenticate
Performing authentication
Authenticated as ......
我们可以在终端中执行以下命令提交自己的作业:
$ python3 ok --submit
如果提交成功,Ok会打印提交ID,可以在课程主页查看评分结果。
=====================================================================
Assignment: lab00
OK, version 2022.09.16
=====================================================================
Submitting lab00 by 210000000 John Smith.
SICP OJ received submission ID xxxxxxxx
Open in browser: https://sicp.pascal-lab.net/2022/oj/assignments
查看评分
打开课程主页,点击右上角的“Online Judge”进入作业系统并登录。
在左边点击一个作业,右边将显示你的所有提交和每一次的提交得分。 每次作业的最终得分为你所有提交的最高得分。
如果你存在学术不端的行为并且被检测出来,你将会看到上图中红色的提示框,且你作业的分数将不再是提交的最高得分。再再再再次提醒,代码抄袭会使得双方的作业成绩都变为0。
常见问题
Q: 作业可以提交多少次?
A: 在截止时间之前(以服务器时间为准)你可以提交任意多的次数。 提交的次数不会影响你的成绩。
Q: 我把电脑借给别人了。别人不小心用我的账号提交了他的代码怎么办?
A: 请马上联系助教说明情况,越早越好,避免误会。
Q: 我来不及完成作业了,怎么办?
A: 原则上不允许作业迟交,没有提交的作业均为0分。如果遇到特殊/紧急情况,请先寻求辅导员的帮助,在QQ上与助教联系,任课教师同意迟交后可以延迟作业提交。
本次实验内容
到此,大家应该顺利地做完并提交了第一道题目。希望这段旅程对大家足够顺利。 接下来,我们还有两道简单的题目让大家再熟悉一下整个实验流程。如果你足够熟练的话,可能几分钟就做完了。 此次实验的截止时间(deadline,也就是DDL)设置为一周,大家不用着急。
Problem 1: 2022 (100pts)
用数字和+
,*
和-
运算符写一个最酷炫的表达式,来替换掉下面twenty_twenty_two
函数中的下划线。
def twenty_twenty_two():
"""Come up with the most creative expression that evaluates to 2022,
using only numbers and the +, *, and - operators.
Expected result:
>>> twenty_twenty_two()
2022
"""
return ______
Problem 2: A + B (100pts)
写一个代表变量 \( a \) 和 \( b \) 之和的算术表达式,来替换掉下面sum
函数中的下划线。
def sum(a, b):
"""Compute the sum of a and b.
Expected result:
>>> sum(1, 2)
3
>>> sum(3, 8)
11
"""
return ______
Problem 3: Diff of Two Squares (100pts)
写一个代表变量 \( a \) 和 \( b \) 的平方差 \( a^2 - b^2 \) 的算术表达式,来替换掉下面diff_square
函数中的下划线。
def diff_square(a, b):
"""Compute the difference of square a and square b.
Expected result:
>>> diff_square(3, 2)
5
>>> diff_square(3, 4)
-7
"""
return ______