原文:Learn Python the Hard Way, 5th Edition (Early Release)
译者:飞龙
协议:CC BY-NC-SA 4.0
模块 1:Python 入门
练习 0:准备工作
这个练习没有代码。这只是你完成的练习,让你的计算机运行 Python。你应该尽可能准确地遵循这些说明。如果你在遵循书面说明时遇到问题,请观看包含的适用于你平台的视频。
通用说明
你的一般任务是获得一个“编程环境”,其中包含你可以用来编写代码的工具。几乎每个程序员都有自己专门的环境,但起初你会想要一些简单的东西,可以帮助你完成这门课程。课程结束后,你将了解足够的编程知识,然后可以浪费余生尝试你能想象到的每种工具。这是非常有趣的。
你需要的是以下内容:
-
Jupyter,将在书的第一部分中用于轻松入门。Jupyter 是一个使用多种语言的编程和数据分析环境,但我们将使用 Python。
-
Python。你安装的 Python 版本基本上不重要,只要它比版本 3.6 旧。Python(和其他软件)的版本使用数字表示它们的年龄,数字的位置决定了版本之间的变化程度。一般规则是第一个数字表示“主要变化”,第二个数字表示“次要变化”,第三个数字表示仅有错误或安全修复。这意味着如果你有版本 3.8 和版本 3.10,那么没有主要变化,但有次要变化。如果你有版本 3.10.1 和 3.10.2,那么只有错误修复。
-
一个基本的程序员编辑器。程序员使用非常复杂的文本编辑器,但你应该从一些简单但仍然作为程序员编辑器的东西开始。
-
终端模拟器。这是一个基于文本的命令界面,用于与计算机交互。如果你看过有关黑客和编程的电影,你会看到人们在黑屏上疯狂输入绿色文本,以便使用他们的“unix exe 32 pipe attack”摧毁整个外星种族。起初你不需要这个,但以后你会“毕业”使用终端,因为它非常强大且学习起来并不太难。
你的计算机上应该已经有大部分你需要的其他东西,所以让我们为你的操作系统(OS)安装这些要求中的每一项。
极简启动
本练习中的说明旨在安装你在课程中所需的大部分工具,但如果你想尽快开始并付出最少的努力,那么请安装:
-
Anaconda 来获取你的 Python。
-
Jupyter 用于编写和运行一些代码。
a. 在 Windows 上运行 Jupyter 的最佳方法是按下 Windows 键(开始菜单)并键入 jupyter-lab
。这将以合理的方式启动它。
b. 在 Linux 上,你应该在终端中输入相同的命令。
c. 在 macOS 上,你可以在终端中输入该命令,或者像平常一样启动应用程序。
这将为您提供足够的信息来开始学习,但最终您会遇到需要使用“命令行”中的终端和 Python 的练习。当您在课程中达到这一点时,请回到这个练习。
完整说明
最终,您将需要安装更多软件来完成课程。书中的安装说明存在的问题是它们很快就会过时。为了解决这个问题,我有一个网页,您需要访问该网页,其中包含所有适用于您的操作系统的安装说明,并附有视频展示安装过程。这些说明会在事物发生变化时进行更新,并且网页包含您书中所需的任何勘误。
要查看这些说明,请访问以下链接:
learncodethehardway.com/setup/python/
如果由于某种原因无法访问此链接,则以下是您需要安装的内容:
-
Anaconda 以获取您的 Python。
-
Jupyter 用于编写和运行一些代码。
-
Geany 用于以后编辑文本。
-
在 Windows 上使用完整安装的Cmder作为您的 shell。
-
在 macOS 上您有终端,Linux 上有您想要的任何东西。
测试您的设置
安装完所有内容后,请按照以下步骤确认一切正常:
-
启动您的终端并精确输入以下命令,包括空格:
mkdir lpthw
。 -
一旦安装成功,您将拥有一个名为
lpthw
的目录,您可以在其中放置您的工作。 -
使用命令
cd lpthw
进入该目录。此命令将您的终端“移动”到该目录,以便您的工作保存在那里。 -
“目录”在 Windows 和 macOS 上也称为“文件夹”。您可以通过在 Windows 上键入
start.
或在 macOS 上键入open.
来在终端中的“目录”和您通常看到的“文件夹”之间建立联系。这将打开当前目录到您通常看到的图形文件夹窗口。如果您迷失了,请键入该命令。 -
start
命令(macOS 上为open
)的作用类似于用鼠标双击那个东西。如果您在终端中想要“打开”某个东西,只需使用此命令。假设有一个名为test.txt
的文本文件,您想在编辑器中打开它。在 Windows 上键入start test.txt
,在 macOS 上键入open test.txt
。 -
现在您可以打开终端并在终端中打开文件,您将需要启动您的编辑器。如果您一直在按照说明操作,这个编辑器就是 Geany。启动它并创建一个名为
test.txt
的文件,然后将其保存在您创建的lpthw
目录中。如果找不到它,请记住您可以在终端中使用start
(macOS 上为open
)打开它,然后使用该文件夹窗口找到它。 -
一旦你把文件保存在
lpthw
目录中,你应该能够在终端中输入ls test.txt
来查看它是否存在。如果出现错误,那么要么你不在lpthw
目录中,需要输入cd ~/lpthw
或者 你把它保存在了错误的地方。请重试直到你能够做到这一点。 -
最后,在终端中输入
jupyter-lab
来启动 Jupyter 并确保它正常工作。它应该会打开你的网页浏览器,然后你会在浏览器中看到 Jupyter 应用程序。这有点像你个人电脑上的一个小网站。
把这些任务看作是一种需要解决的谜题。如果遇到困难,你应该观看我展示如何完成所有操作的适用于你的操作系统的视频。我认为学习这个最好的方法是首先自己尝试;然后当遇到困难时,观看视频看我是如何做的。
学习命令行
现在不需要立即做这个,但如果你在之前的任务中遇到困难,你可能需要通过命令行快速入门课程来学习终端(也称为“命令行”)的基础知识。你暂时不需要这些技能,但命令行是一个非常好的用文字控制计算机的入门,它也会帮助你以后在编程中完成许多其他任务,所以现在学习它只会有好处。
下一步
一旦你把所有东西都搞定了,你就可以继续进行课程的其余部分。如果你遇到问题,可以发邮件给我,邮箱是 help@learncodethehardway.com,我会帮助你。当你给我发邮件求助时,请花时间尽可能详细地描述你的问题,并包含截图。
练习 1:一个好的第一个程序
警告!
如果你跳过了 Exercise 0,那么你就没有正确地进行这本书的学习。你是在尝试使用 IDLE 还是 IDE 吗?我在 Exercise 0 中说不要使用其中的任何一个,所以你也不应该使用。如果你跳过了 Exercise 0,请返回并阅读它。
你应该在 Exercise 0 中花费了相当多的时间学习如何安装 Jupyter,运行 Jupyter,运行终端,并且同时使用它们。如果你还没有这样做,那么请不要继续。你将度过不愉快的时光。这是我唯一一次在开始练习时警告你不要跳过或超前的时间。
在 Jupyter 单元格中输入以下文本:
列表 1.1: ex1.py
1 print("Hello World!")
2 print("Hello Again")
3 print("I like typing this.")
4 print("This is fun.")
5 print('Yay! Printing.')
6 print("I'd much rather you 'not'.")
7 print('I "said" do not touch this.')
你的 Jupyter 单元格应该看起来像这样:
不要担心如果你的 Jupyter 窗口看起来不完全相同;它应该是接近的。你的窗口标题可能略有不同,也许颜色略有不同,而你的 Jupyter 窗口的左侧不会相同,而是会显示你用于保存文件的目录。所有这些差异都是可以接受的。
当你创建这个单元格时,请记住这些要点:
-
我没有在左侧输入行号。这些行号是在书中打印出来的,这样我就可以通过说“看第 5 行…”来谈论特定的行。你不需要在 Python 脚本中输入行号。
-
我在行首有
print
,它看起来与我在单元格中的完全相同。完全意味着完全,不是有点类似。每个字符都必须匹配才能正常工作。颜色无关紧要,只有你输入的字符。
一旦它完全相同,你可以按下SHIFT-ENTER
来运行代码。如果你做对了,那么你应该看到与我在本练习的你应该看到的内容部分相同的输出。如果没有,那么你做错了。不,计算机没有错。
你应该看到的内容
在你按住SHIFT
并按下ENTER
后,Jupyter 的输出将如下所示(我会写成SHIFT-ENTER
):
你可能会看到不同的窗口外观和布局,但重要的是你输入命令并查看输出与我的相同。
如果出现错误,它会看起来像这样:
1 Cell In[1], line 3
2 print("I like typing this.
3 ^
4 SyntaxError: unterminated string literal (detected at line 1)
重要的是你能够阅读这些错误消息,因为你将犯许多这样的错误。即使我也会犯许多这样的错误。让我们逐行查看这个。
-
我们使用
SHIFT-ENTER
在 Jupyter 单元格中运行了我们的命令。 -
Python 告诉我们该单元格在第 3 行有一个错误。
-
它为我们打印出这行代码以供查看。
-
然后它放置一个
^
(插入符)字符指向问题所在的地方。注意结尾缺少"
(双引号)字符了吗? -
最后,它会打印出一个“SyntaxError”并告诉我们可能的错误。通常这些错误非常难以理解,但如果你将该文本复制到搜索引擎中,你会找到其他遇到过这个错误的人,并且你可能会弄清楚如何修复它。
学习练习
学习练习包含你应该尝试做的事情。如果你做不到,跳过它,稍后再回来。
对于这个练习,请尝试这些事情:
-
让你的脚本打印另一行。
-
让你的脚本只打印一行。
-
在一行的开头放一个
#
(井号)字符。它有什么作用?试着找出这个字符的作用。
从现在开始,除非练习有所不同,否则我不会解释每个练习的工作原理。
信息
“井号”也被称为“磅”,“井号”,“网格”或任何一种名称。选择让你放松的那个。
常见学生问题
这些是真实学生在做这个练习时提出的实际问题:
我可以使用 IDLE 吗? 不,现在只使用 Jupyter,稍后我们将使用常规文本编辑器获得额外的超能力。
在 Jupyter 中编辑代码很烦人。我可以使用文本编辑器吗? 完全可以,你也可以在 Jupyter 中创建一个python
文件并获得一个“足够好”的编辑器。在左侧面板中看到所有文件的地方,点击左上角的+
(加号)图标。这将带你到你开始 Jupyter 时看到的第一个屏幕。在底部的$_ Other
下,你会看到一个带有 Python 标志的Python
File
按钮。点击它,你将获得一个编辑器来处理你的文件。
我的代码无法运行;我只是得到一个没有输出的提示符。你很可能字面上采用了我的单元格中的代码,并认为print("Hello World!")
意味着只在单元格中输入"Hello
World!"
,而不包括print
。你的单元格必须完全像我的一样。
练习 2:注释和井号字符
在你的程序中,注释非常重要。它们用于用英语告诉你某件事情的作用,并且用于暂时禁用程序的某些部分。以下是如何在 Python 中使用注释:
列表 2.1:ex2.py
1 # A comment, this is so you can read your program later.
2 # Anything after the # is ignored by python.
3
4 print("I could have code like this.") # and the comment after is ignored
5
6 # You can also use a comment to "disable" or comment out code:
7 # print*(*"This won't run."*)*
8
9 print("This will run.")
从现在开始,我会这样写代码。你需要明白并不是所有东西都必须字面意思。如果我的 Jupyter 看起来与你的有些不同,或者我在使用文本编辑器,结果都是一样的。更多关注文本输出,少关注视觉显示,比如字体和颜色。
你应该看到什么
1 I could have code like this.
2 This will run.
再次强调,我不会展示所有可能的终端的截图。你应该明白上述内容并不是你的输出在视觉上应该看起来的字面翻译,而是你应该关注的文本内容。
学习练习
-
查明你对
#
字符的理解是否正确,并确保你知道它的名称(井号或磅字符)。 -
拿起你的代码,倒着检查每一行。从最后一行开始,逆向检查每个单词是否与你应该输入的相符。
-
你找到更多错误了吗?修正它们。
-
大声朗读你输入的内容,包括按名称说出每个字符。你找到更多错误了吗?修正它们。
常见学生问题
你确定 #
被称为井号字符吗? 我称其为八角符号,因为这是唯一一个没有一个国家使用并且在每个国家都有效的名称。每个国家都认为对于这个字符的命名方式是最重要的,也是唯一的方式。对我来说,这只是傲慢,实际上,大家应该冷静下来,更专注于更重要的事情,比如学习编程。
为什么 print("Hi # there.")
中的 #
不会被忽略? 该代码中的#
在一个字符串内,因此它会一直被放入字符串,直到结束的"
字符出现。字符串中的井号字符只被视为字符,而不是注释。
如何注释掉多行? 在每一行前面加上#
。
我不知道如何在我国的键盘上输入 #
字符。我该怎么做? 一些国家使用 ALT 键和其他键的组合来打印与其语言不同的字符。你需要上网搜索如何输入它。
为什么我要倒着读代码? 这是一个技巧,让你的大脑不会将代码的每个部分赋予意义,这样做可以让你精确处理每个部分。这可以捕捉错误,并且是一个方便的错误检查技术。
练习 3:数字和数学
每种编程语言都有一种处理数字和数学的方式。不要担心:程序员经常谎称自己是数学天才,当他们实际上并不是。如果他们是数学天才,他们会做数学,而不是编写有 bug 的网络框架,以便他们可以开赛车。
这个练习涉及很多数学符号。让我们立即给它们命名,这样你就知道它们叫什么。当你输入时,说出名称。当说起它们感到无聊时,你可以停止说。这里是名称:
-
+
加号 -
-
减号 -
/
斜杠 -
*
星号 -
%
百分号 -
<
小于 -
>
大于 -
<=
小于等于 -
>=
大于等于
注意运算符缺失了吗?在输入这个练习的代码后,回头去弄清楚每个运算符的作用,并完成表格。例如,+
表示加法。
列表 3.1:ex3.py
1 print("I will now count my chickens:")23 print("Hens", 25 + 30 / 6)4 print("Roosters", 100 - 25 * 3 % 4)56 print("Now I will count the eggs:")78 print(3 + 2 + 1 - 5 + 4 % 2 - 1 / 4 + 6)9
10 print("Is it true that 3 + 2 < 5 - 7?")
11
12 print(3 + 2 < 5 - 7)
13
14 print("What is 3 + 2?", 3 + 2)
15 print("What is 5 - 7?", 5 - 7)
16
17 print("Oh, that's why it's False.")
18
19 print("How about some more.")
20
21 print("Is it greater?", 5 > -2)
22 print("Is it greater or equal?", 5 >= -2)
23 print("Is it less or equal?", 5 <= -2)
在运行之前确保你准确地输入了这个。将你的文件的每一行与我的文件进行比较。
你应该看到什么
1 I will now count my chickens:2 Hens 30.03 Roosters 974 Now I will count the eggs:5 6.756 Is it true that 3 + 2 < 5 - 7?7 False8 What is 3 + 2? 59 What is 5 - 7? -2
10 Oh, that's why it's False.
11 How about some more.
12 Is it greater? True
13 Is it greater or equal? True
14 Is it less or equal? False
学习练习
-
在每一行上面,使用
#
写一个注释给自己解释这行代码的作用。 -
你可以直接在 Jupyter 单元格中输入大多数数学运算并获得结果。尝试使用它进行一些基本计算,比如
1+2
,然后按下SHIFT-ENTER
。 -
找到需要计算的内容,并编写一个新的
.py
文件来完成。 -
重写这个练习,使用浮点数使其更准确。
20.0
是浮点数。
常见学生问题
为什么 %
字符是“模数”而不是“百分比”? 主要是设计者选择使用这个符号的方式。在正常的写作中,你正确地将其读作“百分比”。在编程中,这个计算通常使用简单的除法和/
运算符来完成。%
模数是一个不同的操作,只是碰巧使用了%
符号。
%
是如何工作的? 另一种说法是,“X 除以 Y,余数为 J。” 例如,“100 除以 16,余数为 4。” %
的结果是 J 部分,或者剩余部分。
运算的顺序是什么? 在美国,我们使用一个叫做 PEMDAS 的缩写,代表括号 指数 乘法 除法 加法 减法。这也是 Python 遵循的顺序。人们在处理PEMDAS
时常犯的错误是认为这是一个严格的顺序,就像“先做 P,然后 E,然后 M,然后 D,然后 A,然后 S。” 实际的顺序是你先进行乘法 和 除法(M&D)一步完成,从左到右,然后进行加法和减法一步完成,从左到右。因此,你可以将PEMDAS
重写为PE(M&D)(A&S)
。
练习 4:变量和名称
现在你可以用print
打印东西,还可以进行数学运算。下一步是学习关于变量的知识。在编程中,变量只不过是某物的名称,类似于我的名字“Zed”是“写这本书的人类”的名称。程序员使用这些变量名称使他们的代码更像英语,并且因为他们的记忆力不好。如果他们在软件中不使用良好的名称,当他们再次阅读代码时就会迷失方向。
如果你在这个练习中遇到困难,记住你到目前为止学到的找出差异和专注细节的技巧:
-
在每一行上面写一个注释,用英语解释它的作用。
-
反向阅读你的 Python 代码。
-
大声朗读你的 Python 代码,甚至说出字符。
列表 4.1: ex4.py
1 cars = 1002 space_in_a_car = 4.03 drivers = 304 passengers = 905 cars_not_driven = cars - drivers6 cars_driven = drivers7 carpool_capacity = cars_driven * space_in_a_car8 average_passengers_per_car = passengers / cars_driven9
10
11 print("There are", cars, "cars available.")
12 print("There are only", drivers, "drivers available.")
13 print("There will be", cars_not_driven, "empty cars today.")
14 print("We can transport", carpool_capacity, "people today.")
15 print("We have", passengers, "to carpool today.")
16 print("We need to put about", average_passengers_per_car,
17 "in each car.")
信息
space_in_a_car
中的_
被称为下划线字符。如果你还不知道如何输入它,请找出如何输入。我们经常使用这个字符在变量名中的单词之间放置一个虚拟空格。
你应该看到的结果
1 There are 100 cars available.
2 There are only 30 drivers available.
3 There will be 70 empty cars today.
4 We can transport 120.0 people today.
5 We have 90 to carpool today.
6 We need to put about 3.0 in each car.
练习
当我第一次编写这个程序时,我犯了一个错误,Python 像这样告诉我:
1 Traceback (most recent call last):
2 Cell In[1], line 8, in <module>
3 average_passengers_per_car = car_pool_capacity / passenger
4 NameError: name 'car_pool_capacity' is not defined
用你自己的话解释这个错误。确保使用行号并解释原因。
这里有更多练习:
-
我用 4.0 代表
space_in_a_car
,但这是必要的吗?如果只是 4 会发生什么? -
记住 4.0 是一个
浮点数
。它只是一个带有小数点的数字,你需要用 4.0 而不是只有 4,这样它就是浮点数了。 -
在每个变量赋值上面写注释。
-
确保你知道
=
被称为什么(等于号),它的目的是给数据(数字、字符串等)命名(cars_driven
、passengers
)。 -
记住
_
是一个下划线字符。 -
尝试像之前一样从终端运行
python3
作为计算器,并使用变量名进行计算。常用的变量名还有i
、x
和j
。
常见学生问题
=
(单等号)和 ==
(双等号)之间有什么区别? =
(单等号)将右侧的值赋给左侧的变量。==
(双等号)测试两个值是否相同。你以后会学到这个。
我们可以写 x=100
而不是 x = 100
吗? 可以,但这是不好的形式。你应该在操作符周围添加空格,这样更容易阅读。
“反向阅读文件(代码)”是什么意思? 非常简单。想象你有一个有 16 行代码的文件。从第 16 行开始,将其与我在第 16 行的代码进行比较。然后再对第 15 行进行同样的操作,依此类推,直到你将所有代码都反向阅读完。
为什么你在 space_in_a_car
中使用 4.0
? 主要是为了让你了解什么是浮点数,并提出这个问题。参见练习部分。
练习 5:更多变量和打印
现在我们将更多地输入变量并将它们打印出来。这次我们将使用一种称为“格式化字符串”的东西。每当你在文本周围加上"
(双引号)时,你就在制作一个字符串。字符串是你如何制作程序可能提供给人类的东西。你打印字符串,将字符串保存到文件中,将字符串发送到 Web 服务器等等。
字符串非常方便,所以在这个练习中,你将学习如何制作包含嵌入变量的字符串。你通过使用特殊的{}
序列将变量嵌入字符串中,然后将你想要的变量放在{}
字符中。你还必须以字母f
开头,表示“格式”,就像f"Hello {somevar}"
一样。在"
(双引号)和{}
字符之前加上这个小f
告诉 Python 3,“嘿,这个字符串需要格式化。把这些变量放进去。”
和往常一样,即使你不理解也要输入这些内容,并确保完全一样。
列表 5.1:ex5.py
1 my_name = 'Zed A. Shaw'2 my_age = 35 # not a lie3 my_height = 74 # inches4 my_weight = 180 # lbs5 my_eyes = 'Blue'6 my_teeth = 'White'7 my_hair = 'Brown'89 print(f"Let's talk about {my_name}.")
10 print(f"He's {my_height} inches tall.")
11 print(f"He's {my_weight} pounds heavy.")
12 print("Actually that's not too heavy.")
13 print(f"He's got {my_eyes} eyes and {my_hair} hair.")
14 print(f"His teeth are usually {my_teeth} depending on the coffee.")
15
16 # this line is tricky, try to get it exactly right
17 total = my_age + my_height + my_weight
18 print(f"If I add {my_age}, {my_height}, and {my_weight} I get {total}.")
你应该看到的内容
1 Let's talk about Zed A. Shaw.
2 He's 74 inches tall.
3 He's 180 pounds heavy.
4 Actually that's not too heavy.
5 He's got Blue eyes and Brown hair.
6 His teeth are usually White depending on the coffee.
7 If I add 35, 74, and 180 I get 289.
学习扩展
-
将所有变量中的
my_
都去掉。确保你在所有地方都修改了名称,不仅仅是在使用=
设置它们的地方。 -
尝试编写一些变量,将英寸和磅转换为厘米和千克。不要只是输入测量值。在 Python 中进行数学计算。
常见学生问题
我可以像这样定义一个变量吗: 1 = 'Zed Shaw'
? 不可以,1
不是一个有效的变量名。变量名需要以字符开头,所以a1
是可以的,但1
是不行的。
如何将浮点数四舍五入? 你可以像这样使用round()
函数:round(1.7333)
。
为什么我看不懂这个? 尝试将脚本中的数字改为你的测量值。这有点奇怪,但谈论自己会让它看起来更真实。而且,你刚刚开始,所以不会太有意义。继续前进,更多的练习会让你更好地理解。
练习 6:字符串和文本
虽然你一直在写字符串,但你仍然不知道它们是做什么的。在这个练习中,我们创建了一堆带有复杂字符串的变量,这样你就可以看到它们的用途。首先解释一下字符串。
一个字符串通常是你想要向某人显示或从你正在编写的程序“导出”的一小段文本。当你在文本周围放置"
(双引号)或'
(单引号)时,Python 知道你想要的是一个字符串。当你在print
中放置你想要放入字符串中的文本时,你会看到这种情况发生了很多次,放在print
后面的"
或'
中打印字符串。
字符串可以包含在你的 Python 脚本中的任意数量的变量。记住,变量是你设置一个名字=
(等于)一个值的任何代码行。在这个练习的代码中,types_of_people = 10
创建了一个名为types_of_people
的变量,并将其设置为=
(等于)10
。你可以将它放在任何带有{types_of_people}
的字符串中。你还会看到我必须使用一种特殊类型的字符串来“格式化”;它被称为“f-string”,看起来像这样:
f"some stuff here {avariable}"
f"some other stuff {anothervar}"
Python 还有另一种使用.format()
语法的格式化方式,你可以在第 17 行看到。有时候当我想对已经创建的字符串应用格式时,你会看到我使用它。我们稍后会更详细地讨论这个。
现在我们将输入一大堆字符串、变量和格式,并打印它们。你还将练习使用简短的缩写变量名。程序员喜欢通过使用令人讨厌的短小和神秘的变量名来节省时间,所以让我们从早期开始阅读和编写它们。
清单 6.1:ex6.py
1 types_of_people = 102 x = f"There are {types_of_people} types of people."34 binary = "binary"5 do_not = "don't"6 y = f"Those who know {binary} and those who {do_not}."78 print(x)9 print(y)
10
11 print(f"I said: {x}")
12 print(f"I also said: '{y}'")
13
14 hilarious = False
15 joke_evaluation = "Isn't that joke so funny?! {}"
16
17 print(joke_evaluation.format(hilarious))
18
19 w = "This is the left side of..."
20 e = "a string with a right side."
21
22 print(w + e)
你应该看到的内容
1 There are 10 types of people.
2 Those who know binary and those who don't.
3 I said: There are 10 types of people.
4 I also said: 'Those who know binary and those who don't.'
5 Isn't that joke so funny?! False
6 This is the left side of...a string with a right side.
学习扩展
-
浏览这个程序,并在每行上面写一个注释,解释它。
-
找出所有将字符串放在另一个字符串中的地方。
-
你确定只有四个地方吗?你怎么知道?也许我喜欢说谎。
-
解释为什么使用
+
将两个字符串w
和e
相加会得到一个更长的字符串。
破解它
现在你已经到了一个可以尝试破坏你的代码以查看结果的阶段。把这看作是一个游戏,想出最聪明的方法来破坏代码。你也可以找到最简单的方法来破坏它。一旦你破坏了代码,你就需要修复它。如果你有一个朋友,那么你们两个可以尝试破坏对方的代码并修复它。把你的代码给你的朋友,保存在一个名为ex6.py
的文件中,这样他们就可以破坏一些东西。然后你尝试找到他们的错误并修复它。玩得开心,并记住,如果你写过这段代码一次,你可以再次做到。如果你把损坏搞得太严重,你总是可以再次输入以进行额外练习。
常见学生问题
为什么你会在一些字符串周围加上'
(单引号),而在另一些字符串周围不加呢?大多数情况下是出于风格考虑,但我会在双引号内部使用单引号。看看第 6 行和第 15 行,看看我是如何做到这一点的。
如果你觉得这个笑话很有趣,你能写下 hilarious = True
吗? 是的,你以后会更多地了解这些布尔值。
练习 7:合并字符串
现在我们将做一系列练习,你只需输入代码并运行它。我不会解释这个练习,因为它和之前的差不多。目的是提高你的技能。在几个练习后见,不要跳过! 不要粘贴!
列表 7.1: ex7.py
1 print("Mary had a little lamb.")2 print("Its fleece was white as {}.".format('snow'))3 print("And everywhere that Mary went.")4 print("." * 10) # what'd that do?56 end1 = "C"7 end2 = "h"8 end3 = "e"9 end4 = "e"
10 end5 = "s"
11 end6 = "e"
12 end7 = "B"
13 end8 = "u"
14 end9 = "r"
15 end10 = "g"
16 end11 = "e"
17 end12 = "r"
18
19 # watch end = ' ' at the end. try removing it to see what happens
20 print(end1 + end2 + end3 + end4 + end5 + end6, end=' ')
21 print(end7 + end8 + end9 + end10 + end11 + end12)
你应该看到的内容
1 Mary had a little lamb.
2 Its fleece was white as snow.
3 And everywhere that Mary went.
4 ..........
5 Cheese Burger
练习
在接下来的几个练习中,你将有完全相同的练习。
-
回顾并对每一行写下注释。
-
反向阅读或大声朗读每一行,找出你的错误。
-
从现在开始,当你犯错时,记下你犯了什么样的错误。
-
当你进行下一个练习时,看看你犯过的错误,并尽量不在新的练习中犯同样的错误。
-
记住每个人都会犯错。程序员就像魔术师一样,让每个人都以为他们是完美的,从不犯错,但这都是表演。他们经常犯错。
拆分它
你是否在练习 6 中玩得开心?从现在开始,你将打破你写的所有代码或朋友的代码。我不会在每个练习中明确列出拆分它
部分,但我几乎会在每个视频中这样做。你的目标是找到尽可能多的不同方法来破坏你的代码,直到你累了或耗尽所有可能性。在一些练习中,我可能会指出人们常犯的某种特定方式来破坏该练习的代码,但除此之外,请始终将其视为一个命令来始终打破它。
常见学生问题
为什么你使用名为’snow’的变量? 实际上那不是一个变量:它只是一个包含单词snow
的字符串。一个变量不会在单引号中。
像你在练习 1 中说的那样,为每一行代码写一个英文注释是正常的吗? 不,你只需要为难以理解的代码或者为什么要这样做写注释。为什么通常更重要,然后你尝试编写代码以解释某个操作是如何完成的。然而,有时你必须编写一些糟糕的代码来解决问题,这时确实需要在每一行上写注释。在这种情况下,这仅仅是为了让你练习将代码翻译成英文。
我可以使用单引号或双引号来创建一个字符串吗?它们有不同的作用吗? 在 Python 中,用任何一种方式创建字符串都是可以接受的,尽管通常你会在像'a'
或'snow'
这样的短字符串中使用单引号。
练习 8:手动格式化字符串
现在我们将看到如何对字符串进行更复杂的格式化。这段代码看起来复杂,但如果你在每一行上面做好注释,并将每个部分分解开来,你就会理解它。
代码清单 8.1: ex8.py
1 formatter = "{} {} {} {}"23 print(formatter.format(1, 2, 3, 4))4 print(formatter.format("one", "two", "three", "four"))5 print(formatter.format(True, False, False, True))6 print(formatter.format(formatter, formatter, formatter, formatter))7 print(formatter.format(8 "Try your",9 "Own text here",
10 "Maybe a poem",
11 "Or a song about fear"
12 ))
你应该看到的内容
1 1 2 3 4
2 one two three four
3 True False False True
4 {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {}
5 Try your Own text here Maybe a poem Or a song about fear
在这个练习中,我使用了一个叫做“函数”的东西,将 formatter
变量转换为其他字符串。
当你看到我写 formatter.format(...)
时,我是在告诉 Python 执行以下操作:
-
取出第 1 行定义的
formatter
字符串。 -
调用它的
format
函数,类似于告诉它执行一个名为format
的命令行命令。 -
传递给
format
四个参数,这些参数与formatter
变量中的四个{}
匹配。这就像向命令行命令format
传递参数一样。 -
在
formatter
上调用format
的结果是一个新字符串,其中的{}
被这四个变量替换。这就是print
现在打印出来的内容。
这对于第八个练习来说有点多,所以我希望你把它当作一个脑筋急转弯。如果你不是真的理解发生了什么,也没关系,因为本书的其余部分会慢慢澄清这一点。此时,请尝试研究一下这个,并看看发生了什么,然后继续下一个练习。
学习任务
重复 练习 7 中的学习任务。
常见学生问题
为什么我必须在“one”周围加引号,但不需要在 True
或 False
周围加引号? Python 将 True
和 False
视为代表真和假概念的关键字。如果你在它们周围加上引号,那么它们就会变成字符串,无法正常工作。你将在后面学到更多关于它们如何工作的知识。
我可以使用 IDLE 运行吗? 不可以,如果你知道的话,应该使用 Jupyter 或命令行。学习编程是必不可少的,如果你想学习编程,这是一个很好的起点。Jupyter 比 IDLE 是一个更优秀的工具。
练习 9:多行字符串
现在你应该意识到这本书的模式是使用多个练习来教授你新知识。我从你可能不理解的代码开始,然后更多的练习来解释概念。如果你现在不理解某些内容,随着完成更多练习,你以后会理解的。记下你不理解的内容,然后继续。
代码清单 9.1: ex9.py
1 # Here's some new strange stuff, remember type it exactly.23 days = "Mon Tue Wed Thu Fri Sat Sun"4 months = "Jan\nFeb\nMar\nApr\nMay\nJun\nJul\nAug"56 print("Here are the days: ", days)7 print("Here are the months: ", months)89 print("""
10 There's something going on here.
11 With the three double-quotes.
12 We'll be able to type as much as we like.
13 Even 4 lines if we want, or 5, or 6.
14 """)
你应该看到的内容
1 Here are the days: Mon Tue Wed Thu Fri Sat Sun2 Here are the months: Jan3 Feb4 Mar5 Apr6 May7 Jun8 Jul9 Aug
10
11 There's something going on here.
12 With the three double-quotes.
13 We'll be able to type as much as we like.
14 Even 4 lines if we want, or 5, or 6.
学习扩展
重复来自练习 7 的学习扩展。
常见学生问题
为什么我在三个双引号之间放空格时会出错? 你必须像这样输入"""
而不是" " "
, 意思是每个之间都没有空格。
如果我想要在新的一行开始月份怎么办? 你只需像这样以\n
开头的字符串:"\nJan\nFeb\nMar\nApr\nMay\nJun\nJul\nAug"
。
我的错误总是拼写错误,这是不好的吗? 大多数编程错误在开始阶段(甚至后来)都是简单的拼写错误、打字错误或者简单事情的顺序错了。
第 10 题. 字符串中的转义代码
在第 9 题中,我给你一些新东西,只是为了让你保持警惕。我向你展示了两种跨越多行的字符串的方法。在第一种方法中,我在月份名称之间放置了字符\n
(反斜杠n
)。这两个字符在该点将一个换行字符
放入字符串中。
这个\
(反斜杠)字符将难以输入的字符编码到字符串中。有各种不同的“转义序列”可用于你可能想要使用的不同字符。我们将尝试一些这些序列,这样你就能明白我的意思。
一个重要的转义序列是转义单引号'
或双引号"
。想象一下,你有一个使用双引号的字符串,而你想在字符串中放一个双引号。如果你写"我 "理解" 乔。"
,那么 Python 会感到困惑,因为它会认为"
在"理解"
周围实际上结束了字符串。你需要一种方法告诉 Python,字符串中的"
不是真正的双引号。
要解决这个问题,你需要转义双引号和单引号,这样 Python 才知道将它们包含在字符串中。这里有一个例子:
"I am 6'2\" tall." # escape double-quote inside string
'I am 6\'2" tall.' # escape single-quote inside string
解决这个问题的第二种方法是使用三引号,即"""
,它的工作方式类似于字符串,但你也可以放置任意行的文本,直到再次键入"""
。我们也会玩一下这些。
代码清单 10.1: ex10.py
1 tabby_cat = "\tI'm tabbed in."2 persian_cat = "I'm split\non a line."3 backslash_cat = "I'm \\ a \\ cat."45 fat_cat = """6 I'll do a list:7 \t* Cat food8 \t* Fishies9 \t* Catnip\n\t* Grass
10 """
11
12 print(tabby_cat)
13 print(persian_cat)
14 print(backslash_cat)
15 print(fat_cat)
你应该看到的内容
寻找你制作的制表符。在这个练习中,正确的间距很重要。
1 I'm tabbed in.2 I'm split3 on a line.4 I'm \ a \ cat.56 I'll do a list:7 * Cat food8 * Fishies9 * Catnip
10 * Grass
转义序列
这是 Python 支持的所有转义序列。你可能不会使用其中许多,但无论如何要记住它们的格式和功能。尝试在一些字符串中使用它们,看看能否让它们起作用。
学习练习
-
通过将它们放在闪存卡上来记忆所有的转义序列。
-
使用
'''
(三个单引号)代替。你能看出为什么你可能会使用它而不是"""
吗? -
结合转义序列和格式字符串创建更复杂的格式。
常见学生问题
我还没有完全弄清楚最后一个练习。我应该继续吗? 是的,继续。不要停下来,记下你对每个练习不理解的事情。定期查看你的笔记,看看在完成更多练习后是否能弄清楚这些事情。有时候,你可能需要回头做几个练习。
是什么让 // 与其他的不同? 这只是你会写出一个反斜杠(\
)字符的方式。想想为什么你会需要这个。
当我写 //
或 /n
时它不起作用。那是因为你使用的是正斜杠/
而不是反斜杠\
。它们是不同的字符,做着非常不同的事情。
我不明白练习 3。你说的“结合”转义序列和格式是什么意思? 我需要你理解的一个概念是,这些练习可以结合起来解决问题。利用你对格式化字符串的了解,编写一些新代码,使用格式化字符串和这个练习中的转义序列。
哪个更好, '''
还是 """
? 这完全取决于风格。现在选择'''
(三个单引号)风格,但要准备根据感觉或其他人的做法选择其中之一。
练习 11:向人们提问
现在是加快节奏的时候了。你一直在打印以便熟悉输入简单的东西,但那些简单的东西相当无聊。我们现在想要做的是将数据输入到你的程序中。这有点棘手,因为你必须学会做两件可能一开始不太明白的事情,但相信我,无论如何都要做。在几个练习后,它们会变得清晰起来。
软件大部分的功能是以下内容:
-
从一个人那里获取某种输入。
-
改变它。
-
打印出一些内容以展示它是如何改变的。
到目前为止,你一直在打印字符串,但还没有能够从一个人那里获取任何输入。你可能甚至不知道“输入”是什么意思,但无论如何都要输入这段代码,并确保完全相同。在下一个练习中,我们将做更多的解释输入的内容。
清单 11.1:ex11.py
1 print("How old are you?", end=' ')
2 age = input()
3 print("How tall are you?", end=' ')
4 height = input()
5 print("How much do you weigh?", end=' ')
6 weight = input()
7
8 print(f"So, you're {age} old, {height} tall and {weight} heavy.")
信息
我们在每个打印行的末尾加上了end=' '
。这告诉print
不要以换行符结束该行并转到下一行。
你应该看到的内容
1 How old are you? 38
2 How tall are you? 6'2"
3 How much do you weigh? 180lbs
4 So, you're 38 old, 6'2" tall and 180lbs heavy.
学习练习
-
上网查找 Python 的
input
是做什么的。 -
你能找到其他使用它的方法吗?尝试一些你找到的示例。
-
写另一个像这样的“表格”来询问其他问题。
常见学生问题
我如何从某人那里获取一个数字以便进行数学计算? 这有点高级,但尝试x =
int(input())
,它从input()
获取数字作为字符串,然后使用int()
将其转换为整数。
我使用 input("6'2")
将我的身高输入到原始输入中,但它不起作用。你不需要在那里输入你的身高;你直接在终端中输入。首先,回去把代码完全改成和我的一样。接下来,运行脚本,当它暂停时,在键盘上输入你的身高。就是这么简单。
练习 12:更简单的提示方式
当你输入input()
时,你实际上输入了(
和)
字符,这些是括号
字符。对于input
,你也可以输入一个提示,让人知道该输入什么。在()
内放入你想要的提示字符串,看起来像这样:
y = input("Name? ")
这提示用户输入“姓名?”,并将结果放入变量y
中。这就是你向某人提问并得到答案的方式。
这意味着我们可以完全重写我们之前的练习,只需使用input
来进行所有提示。
列表 12.1: ex12.py
1 age = input("How old are you? ")
2 height = input("How tall are you? ")
3 weight = input("How much do you weigh? ")
4
5 print(f"So, you're {age} old, {height} tall and {weight} heavy.")
你应该看到什么
1 How old are you? 38
2 How tall are you? 6'2"
3 How much do you weigh? 180lbs
4 So, you're 38 old, 6'2" tall and 180lbs heavy.
学习练习
-
在你的 Jupyter 单元格中右键点击任何
print
,然后选择显示上下文帮助
。这将为print
提供快速文档。 -
如果你这样做,面板上会显示“点击函数查看文档。”,那么你需要用
SHIFT-ENTER
运行代码,然后再次点击print
函数。 -
接下来,去Google搜索
python print site:python.org
以获取 Pythonprint
函数的官方文档。
常见学生问题
为什么上下文帮助会消失? 我不确定,但我怀疑它无法在你编辑代码时找到你想要文档的函数。运行代码,然后突然它就会起作用。你也可以点击你工作的任何其他单元格中的任何其他函数。
这些文档是从哪里来的? 这些是添加到代码本身的文档注释,这就是为什么它可能与在线文档不同的原因。养成在可能的情况下同时学习两者的习惯。
练习 13:参数、解包、变量
现在我们将快速进入终端
(又称PowerShell
)版本的python
世界。如果你正确完成了First Steps,你应该已经学会了如何启动终端并运行一个简单的 Python 脚本。在本课程的后面,你将学习如何更广泛地使用终端,但在这个练习中,我们只是做一个小小的测试。
首先,我希望你使用 Jupyter 的新 Python 文件创建一个名为ex13.py
的文件:
-
左侧有一个列出你目录中文件的列表。
-
在那个列表的上方有一个蓝色的
[+]
按钮。 -
点击那个按钮,滚动到底部,那里应该有一个带有 Python“蓝色和黄色蛇”标志的
Python
File
按钮。 -
点击那个按钮打开一个新的面板,你可以在其中输入代码。
-
立即使用鼠标选择
File > Save Python File
或按住CTRL
键并按下s
键(通常显示为Ctrl-S
,但你不需要按住 Shift 键来输入S
)。 -
这将打开一个模态提示,上面写着“重命名文件”。输入“ex13”,它应该保留
.py
,但确保这个输入显示为ex13.py
。 -
点击蓝色的
[Rename]
按钮将文件保存在那个目录中。
保存了那个文件之后,你可以将以下代码输入到文件中:
列表 13.1: ex13.py
1 from sys import argv
2 # read the What You Should See section for how to run this
3 script, first, second, third = argv
4
5 print("The script is called:", script)
6 print("Your first variable is:", first)
7 print("Your second variable is:", second)
8 print("Your third variable is:", third)
我建议你只输入一两行代码,然后执行以下操作:
-
再次保存你的文件。按下
CTRL-s
是最简单的方法,但如果你记不住,可以使用菜单。这次它不应该要求你“重命名”文件,而应该直接保存。 -
你的文件现在保存在你的项目目录中。如果你还记得*First Steps*部分,你创建了一个目录在
~/Projects/lpythw
,当你运行jupyter-lab
时,你首先cd ~/Projects/lpythw
。 -
现在打开一个新的终端(在 Windows 上是 PowerShell),再次输入
cd ~/Projects/lpythw/
以进入该终端。 -
最后,输入
python ex13.py first 2nd 3rd
。(在终端中输入时不要加句号。)当你这样做时,你应该看到绝对什么都没有!是的,这点非常重要。你只输入了一两行代码,所以在你的代码中没有print
语句。这意味着它不会打印任何内容,但这是好事。如果出现错误,那么停下来弄清楚你做错了什么。你是不是打错了那行代码?你运行了python ex13.py
吗?那也是错误的。你必须运行python ex13.py first 2nd 3rd
。(再次强调,不要在终端中加句号。)
如果你迷路了
如果你对自己所在位置感到困惑,可以在 macOS 上使用open
命令,在 Windows 上使用start
命令。如果你输入以下内容:
1 open .
在 macOS 电脑上,它会打开一个窗口,显示当前终端所在位置的内容。当你输入以下内容时,同样的情况也会发生:
1 start .
在 Windows 中在 PowerShell 中。这样做将帮助你将“文件在窗口中的文件夹中”这个概念连接到“文件在终端(PowerShell)中的目录中”。
如果这是你第一次看到这个建议,那么回到*First Steps*部分,重新查看它,因为你似乎错过了这个重要概念。
代码描述
在第1
行,我们有一个称为“import”的东西。这是你从 Python 功能集中添加功能到你的脚本的方式。Python 不会一次性给你所有功能,而是要求你说出你打算使用的功能。这样可以使你的程序保持简洁,同时也作为其他程序员阅读你代码时的文档。
argv
是“参数变量”,在编程中是一个非常标准的名称,你会发现它在许多其他语言中被使用。这个变量保存你在运行 Python 脚本时传递的参数。在练习中,你将有机会更多地玩弄它,并看看会发生什么。
第 3 行“unpacks” argv
,这样,它不再保存所有参数,而是被分配给四个你可以使用的变量:script
、first
、second
和third
。这可能看起来很奇怪,但“unpack”可能是最好的描述它的词。它只是说,“取出argv
中的任何内容,解包它,并按顺序分配给左边的所有这些变量。”
之后我们就像平常一样打印它们出来。
等一下!features 还有另一个名字
我在这里称它们为“features”(你import
来使你的 Python 程序做更多事情的小东西),但没有人称它们为 features。我只是用这个名字是因为我需要欺骗你学习它们是什么,而不带有行话。在继续之前,你需要学习它们的真实名称:modules
。
从现在开始,我们将称这些为“features”,我们import
modules。我会说像,“你想要导入sys
模块。”其他程序员也称它们为“库”,但让我们坚持使用模块。
你应该看到的内容
警告!
注意!你一直在没有命令行参数运行 Python 脚本。如果你只输入python3 ex13.py
,那么你做错了!请仔细看我是如何运行的。每当看到使用 argv 时都适用。
当你输入完所有代码后,它应该像这样最终运行(而且你必须传递三个命令行参数):
1 $ python ex13.py first 2nd 3rd
2 The script is called: ex13.py
3 Your first variable is: first
4 Your second variable is: 2nd
5 Your third variable is: 3rd
这是你使用不同参数进行几次运行时应该看到的内容:
1 $ python ex13.py stuff things that
2 The script is called: ex13.py
3 Your first variable is: stuff
4 Your second variable is: things
5 Your third variable is: that
这里有一个更多的例子,显示它可以是任何东西:
1 $ python ex13.py apple orange grapefruit
2 The script is called: ex13.py
3 Your first variable is: apple
4 Your second variable is: orange
5 Your third variable is: grapefruit
你实际上可以用任何三个你想要的东西替换first
、2nd
和3rd
。
如果你没有正确运行它,那么你会得到这样的错误:
命令失败:python ex13.py first 2nd Traceback (most recent call last): File “/Users/zedshaw/Project s/learncodethehardway.com/private/db/modules/learn-python-the-hard-way-5e-section-1/code/ex13.py”,第 3 行,在脚本、第一个、第二个、第三个 = argv ValueError: not enough values to unpack (expected 4, got 3)
当你在运行时没有在命令中放足够的参数时会发生这种情况(在这种情况下只有first 2nd
)。注意,当我运行它时,我给了它first 2nd
,这导致它出现了一个关于“需要超过 3 个值来解包”的错误,告诉你没有给足够的参数。
学习练习
-
尝试给你的脚本提供少于三个参数。看看你会得到什么错误?看看你能否解释清楚。
-
编写一个参数较少的脚本和一个参数较多的脚本。确保给解包的变量起一个好名字。
-
结合
input
和argv
编写一个脚本,从用户那里获取更多输入。不要想得太多。只需使用argv
获取一些内容,然后使用input
从用户那里获取其他内容。 -
记住模块给你提供了功能。模块。模块。记住这一点,因为我们以后会用到它。
常见学生问题
当我运行它时,我得到 ValueError: need more than 1 value to unpack
。记住一个重要的技能是注意细节。如果你看一下你应该看到的内容部分,你会看到我是如何在命令行上运行脚本的。你应该完全复制我运行它的方式。那里还有一个巨大的警告解释了你刚刚犯的错误,所以请再次注意。
argv
和 input()
之间有什么区别? 区别在于用户需要在哪里提供输入。如果他们在命令行上给你的脚本输入,那么使用argv
。如果你希望他们在脚本运行时使用键盘输入,那么使用input()
。
命令行参数是字符串吗? 是的,它们作为字符串传入,即使你在命令行上输入了数字。使用int()
来转换它们,就像使用int(input())
一样。
你如何使用命令行? 你应该已经学会如何快速流利地使用它了,但如果你在这个阶段需要学习,那么请阅读附录 A,“命令行速成课程”。
我无法将 argv
与 input()
结合起来。不要想得太多。只需在脚本末尾加上两行,使用input()
获取一些内容然后打印出来。从那里开始尝试更多同时使用两者的方法。
为什么我不能这样做 input('? ') = x
? 因为这是反向的工作方式。按照我的方式去做,它就会起作用。
为什么你要让我一次只输入一行? 初学者和专业人士最常犯的错误就是他们输入一大块代码,运行一次,然后因为所有的错误而哭泣。编程语言中的错误令人沮丧,并经常指向源代码中错误的位置。如果你一次只输入几行代码,你会更频繁地运行代码,当出现错误时,你知道这可能是你刚刚输入的那几行代码有问题。当你输入 100 行代码时,你将花费接下来的 5 天来寻找所有的错误,最终放弃。省点麻烦,一次只输入一点点。这就是我和大多数有能力的程序员在现实生活中所做的。
练习 14:提示和传递
让我们做一个练习,结合使用argv
和input
来询问用户特定的事情。你将在下一个练习中需要这个,那里你将学习如何读写文件。在这个练习中,我们将稍微不同地使用input
,让它打印一个简单的>
提示。
列表 14.1: ex14.py
1 from sys import argv23 script, user_name = argv4 prompt = '> '56 print(f"Hi {user_name}, I'm the {script} script.")7 print("I'd like to ask you a few questions.")8 print(f"Do you like me {user_name}?")9 likes = input(prompt)
10
11 print(f"Where do you live {user_name}?")
12 lives = input(prompt)
13
14 print("What kind of computer do you have?")
15 computer = input(prompt)
16
17 print(f"""
18 Alright, so you said {likes} about liking me.
19 You live in {lives}. Not sure where that is.
20 And you have a {computer} computer. Nice.
21 """)
我们创建一个名为prompt
的变量,设置为我们想要的提示,并将其提供给input
,而不是一遍又一遍地输入。现在,如果我们想要将提示更改为其他内容,我们只需在这一个地方更改它,然后重新运行脚本。非常方便。
警告!
记住,你必须像在 Exercise 13 中那样做,并使用终端使其工作。这将是一段时间内的最后一次,但重要的是要知道如何从终端运行代码,因为这是运行 Python 代码的一种常见方式。
你应该看到的内容
运行此代码时,请记住必须为argv
参数提供你的名字。
1 $ python ex14.py zed2 Hi zed, I'm the ex14.py script.3 I'd like to ask you a few questions.4 Do you like me zed?5 > Yes6 Where do you live zed?7 > San Francisco8 What kind of computer do you have?9 > Tandy 1000
10
11 Alright, so you said Yes about liking me.
12 You live in San Francisco. Not sure where that is.
13 And you have a Tandy 1000 computer. Nice.
学习练习
-
找出 Zork 和 Adventure 是什么游戏。尝试找到一份副本并玩一玩。
-
将
prompt
变量完全更改为其他内容。 -
添加另一个参数,并在你的脚本中使用它,就像在上一个练习中使用
first, second = ARGV
一样。 -
确保你理解我是如何将
"""
样式的多行字符串与{}
格式激活器结合在一起作为最后一个打印的。 -
尝试找到在 Jupyter 中运行此代码的方法。你可能需要用其他东西替换使用
argv
的代码,比如一些变量。
常见学生问题
当我运行这个脚本时,我收到 SyntaxError: invalid syntax
。再次强调,你必须在命令行上正确运行它,而不是在 Python 内部。如果你输入python3
然后尝试输入python3 ex14.py Zed
,它将失败,因为你是在Python 内部运行 Python。关闭窗口,然后只需输入python3 ex14.py Zed
。
我不明白你所说的改变提示是什么意思。看看变量prompt = '> '
。将其更改为其他值。你知道这个;这只是一个字符串,你已经做了 13 个练习来创建它,所以花点时间弄清楚。
我收到错误 ValueError: need more than 1 value to unpack
。记得我说过你需要查看你应该看到的内容(WYSS)部分并复制我做的吗?你需要在这里做同样的事情,关注我如何输入命令以及为什么要有命令行参数。
我如何从 IDLE 运行这个? 不要使用 IDLE。它很糟糕。
我可以为 prompt
变量使用双引号吗? 完全可以。试试看吧。
你有一台 Tandy 电脑吗? 我小时候有过。
当我运行它时,我收到 NameError: name 'prompt' is not defined
。你要么拼错了prompt
变量的名称,要么忘记了那一行。回去逐行比较我的代码和你的代码,从脚本底部到顶部。每当你看到这个错误时,意味着你拼写错了或忘记创建变量。
练习 15:读取文件
你知道如何使用input
或argv
从用户那里获取输入。现在你将学习如何从文件中读取。你可能需要仔细研究这个练习,以理解发生了什么,所以仔细做练习并记住你的检查。如果不小心处理文件,这是一种擦除你的工作的简单方法。
这个练习涉及编写两个文件。一个是你将运行的通常的ex15.py
文件,但另一个名为ex15_sample.txt
。这第二个文件不是一个脚本,而是一个我们将在我们的脚本中读取的纯文本文件。以下是该文件的内容:
1 This is stuff I typed into a file.
2 It is really cool stuff.
3 Lots and lots of fun to have in here.
我们想要在我们的脚本中“打开”那个文件并将其打印出来。然而,我们不想将名为ex15_sample.txt
的文件名直接“硬编码”到我们的脚本中。所谓“硬编码”是指将应该来自用户的一些信息作为字符串直接放在我们的源代码中。这是不好的,因为我们希望以后加载其他文件。解决方案是使用argv
或input
询问用户要打开哪个文件,而不是将文件名“硬编码”到脚本中。
列表 15.1:ex15.py
1 from sys import argv23 script, filename = argv45 txt = open(filename)67 print(f"Here's your file {filename}:")8 print(txt.read())9
10 print("Type the filename again:")
11 file_again = input("> ")
12
13 txt_again = open(file_again)
14
15 print(txt_again.read())
这个文件中有一些花哨的东西,所以让我们快速地分解一下。
第 1-3 行使用argv
获取文件名。接下来是第 5 行,我们使用一个新命令:open
。现在运行pydoc open
并阅读说明。注意,就像你自己的脚本和input
一样,它接受一个参数并返回一个可以设置为你自己变量的值。你刚刚打开了一个文件。
第 7 行打印了一条小消息,但在第 8 行,我们有一些非常新颖和令人兴奋的东西。我们在txt
上调用了一个名为read
的函数。你从open
得到的是一个file
,它也有你可以给它的命令。你可以使用.
(点)命令一个文件,命令的名称和参数,就像open
和input
一样。不同之处在于txt.read()
表示,“嘿txt
!执行你的读取命令,不带参数!”
文件的其余部分基本相同,但我们将在学习练习部分留给你来分析。
你应该看到什么
警告!
注意!我说了要注意!你之前只是用脚本的名称运行脚本,但现在你正在使用argv
,你必须添加参数。看看以下示例的第一行,你会看到我执行python ex15.py ex15_sample.txt
来运行它。在ex15.py
脚本名称后面看到额外的参数ex15_sample.txt
。如果你不输入,你会得到一个错误,所以要注意!
我创建了一个名为ex15_sample.txt
的文件并运行了我的脚本。
1 Here's your file ex15_sample.txt:2 This is stuff I typed into a file.3 It is really cool stuff.4 Lots and lots of fun to have in here.567 Type the filename again:8 > ex15_sample.txt9 This is stuff I typed into a file.
10 It is really cool stuff.
11 Lots and lots of fun to have in here.
学习练习
这是一个很大的飞跃,所以在继续之前,请确保你尽力完成这些学习练习。
-
在每一行上面,用英语写出那行代码的作用。
-
如果你不确定,向别人寻求帮助或在网上搜索。很多时候搜索“python3 THING”会找到关于 Python 中那个 THING 做什么的答案。尝试搜索“python3 open”。
-
我在这里使用了“命令”这个词,但命令也被称为“函数”和“方法”。你将在本书后面学习有关函数和方法的知识。
-
删除使用
input
并再次运行脚本的 10-15 行。 -
只使用
input
,尝试以这种方式运行脚本。为什么有一种获取文件名的方式比另一种更好? -
启动
python3
以启动python3
shell,并从提示符中像在这个程序中一样使用open
。注意你如何可以在python3
中打开文件并运行read
? -
让你的脚本也在
txt
和txt_again
变量上调用close()
。在完成文件操作后关闭文件是很重要的。
常见学生问题
txt = open(filename)
是否返回文件的内容? 不,它不会。它实际上创建了一个叫做“文件对象”的东西。你可以把文件想象成 50 年代大型计算机上看到的旧磁带驱动器,甚至像今天的 DVD 播放器。你可以在其中移动,然后“读取”它们,但 DVD 播放器不是 DVD,就像文件对象不是文件内容一样。
我无法像你在第 7 个学习任务中说的那样在终端/PowerShell 中输入代码。首先,从命令行中只需输入python3
并按 Enter。现在你在python3
中,就像我们之前做过几次一样。然后你可以输入代码,Python 会逐段运行它。尝试一下。要退出,请输入quit()
并按 Enter。
为什么我们打开文件两次时没有错误? Python 不会限制你多次打开文件,有时这是必要的。
from sys import argv
是什么意思? 现在只需理解sys
是一个包,这个短语只是说从那个包中获取argv
功能。你以后会学到更多。
我将文件名放在 script, ex15_sample.txt = argv
中,但它不起作用。不,这不是你应该做的。确保代码与我的完全一样,然后像我一样从命令行运行它。你不需要放文件名进去;让 Python 放进去。
练习 16:读写文件
如果你做了上一个练习的学习练习,你应该看到各种可以给文件的命令(方法/函数)。这是我希望你记住的命令列表:
-
close
– 关闭文件。就像文本编辑器或文字处理器中的文件->保存..
一样。 -
read
– 读取文件的内容。你可以将结果赋值给一个变量。 -
readline
– 读取文本文件的一行。 -
truncate
– 清空文件。如果你关心文件的话要小心。 -
write('stuff')
– 将“stuff”写入文件。 -
seek(0)
– 将读/写位置移动到文件的开头。
记住每个命令的一种方法是想象一下黑胶唱片、磁带、VHS 磁带、DVD 或 CD 播放器。在计算机的早期,数据存储在这些媒体上,所以许多文件操作仍然类似于一个线性存储系统。磁带和 DVD 驱动器需要“寻找”到一个特定的位置,然后你可以在那个位置读取或写入。今天我们有操作系统和存储介质模糊了随机存取内存和磁盘驱动器之间的界限,但我们仍然使用一个必须移动的线性磁带的读/写头的旧概念。
目前,这些是你需要知道的重要命令。其中一些需要参数,但我们并不真的关心。你只需要记住write
需要一个你想写入文件的字符串参数。
让我们利用其中的一些内容制作一个简单的文本编辑器:
列表 16.1: ex16.py
1 filename = "test.txt"23 print(f"We're going to erase {filename}.")4 print("If you don't want that, hit CTRL-C *(*^C*)*.")5 print("If you do want that, hit RETURN.")67 input("?")89 print("Opening the file...")
10 target = open(filename, 'w')
11
12 print("Truncating the file. Goodbye!")
13 target.truncate()
14
15 print("Now I'm going to ask you for three lines.")
16
17 line1 = input("line 1: ")
18 line2 = input("line 2: ")
19 line3 = input("line 3: ")
20
21 print("I'm going to write these to the file.")
22
23 target.write(line1)
24 target.write("\n")
25 target.write(line2)
26 target.write("\n")
27 target.write(line3)
28 target.write("\n")
29
30 print("And finally, we close it.")
31 target.close()
那是一个很大的文件,可能是你输入的最大的文件。所以慢慢来,检查一下,经常运行,慢慢来。一个技巧是一次运行一部分。先运行 1-2 行,然后再运行两行,再运行几行,直到全部完成并运行。
你应该看到的内容
实际上你会看到两件事。首先是你新脚本的输出:
1 We're going to erase test.txt.2 If you don't want that, hit CTRL-C (^C).3 If you do want that, hit RETURN.4 ?5 Opening the file...6 Truncating the file. Goodbye!7 Now I'm going to ask you for three lines.8 line 1: Mary had a little lamb9 line 2: Its fleece was white as snow
10 line 3: It was also tasty
11 I'm going to write these to the file.
12 And finally, we close it.
现在,打开你创建的文件(在我的案例中是test.txt
),使用 Jupyter 的左侧面板查看一下。整洁,对吧?
学习练习
-
如果你不理解这个,回过头来,使用注释技巧来弄清楚。在每一行上加一个简单的英文注释将帮助你理解,或者至少让你知道你需要更多地研究。
-
编写一个类似于上一个练习 14 的
.py
脚本,使用read
(练习 15)和argv
(练习 13)来读取你刚刚创建的文件。确保你在终端/PowerShell 中运行而不是在 Jupyter 中。 -
这个文件中有太多的重复。使用字符串、格式和转义来用一个
target.write()
命令打印出line1
、line2
和line3
,而不是六个命令。 -
找出为什么我们需要将
'w'
作为open
的额外参数传递。提示:open
试图通过让你明确表示你要写入一个文件来保持安全。 -
如果以**'w’模式打开文件,那么你真的需要target.truncate()吗?阅读 Python 的open**函数的文档,看看这是否属实。
常见学生问题
在使用 ‘w’ 参数时, truncate()
是必需的吗? 参见学习任务 5。
‘w’ 代表什么? 实际上,它只是一个包含文件模式字符的字符串。如果使用**‘w’,那么你是在说“以‘写’模式打开此文件”,这就是’w’** 字符的原因。还有**'r’代表“读取”,‘a’**代表追加,以及这些的修饰符。
我可以使用哪些文件模式的修饰符? 现在最重要的是要知道**+修饰符,这样你就可以使用’w+','r+‘和’a+’**。这将以读取和写入模式打开文件,并根据使用的字符,以不同的方式定位文件。
只需执行 open(filename) 就会以 ‘r’ (读取)模式打开文件吗? 是的,这是**open()**函数的默认设置。
练习 17:更多文件
现在让我们做更多关于文件的事情。我们将编写一个 Python 脚本将一个文件复制到另一个文件。这将非常简短,但会给你关于文件的其他操作想法。
列表 17.1:ex17.py
1 from sys import argv2 from os.path import exists34 from_file = "test.txt"5 to_file = "new_test.txt"67 print(f"Copying from {from_file} to {to_file}")89 # we could do these two on one line, how?
10 in_file = open(from_file)
11 indata = in_file.read()
12
13 print(f"The input file is {len*(*indata*)*} bytes long")
14
15 print(f"Does the output file exist? {exists*(*to_file*)*}")
16 print("Ready, hit RETURN to continue, CTRL-C to abort.")
17 input()
18
19 out_file = open(to_file, 'w')
20 out_file.write(indata)
21
22 print("Alright, all done.")
23
24 out_file.close()
25 in_file.close()
你应该立即注意到我们import
了另一个方便的命令叫做exists
。如果文件存在,它会返回True
,基于它的名称作为字符串参数。如果不存在,则返回False
。我们将在本书的后半部分使用这个函数来做很多事情,但现在你应该看看如何导入它。
使用import
是一种获取其他更好(通常是)程序员编写的大量免费代码的方法,这样你就不必自己编写它。
你应该看到的内容
就像你的其他脚本一样,用两个参数运行这个脚本:要复制的文件和要复制到的文件。我将使用一个名为test.txt
的简单测试文件:
1 Copying from test.txt to new_test.txt
2 The input file is 70 bytes long
3 Does the output file exist? True
4 Ready, hit RETURN to continue, CTRL-C to abort.
5
6 Alright, all done.
它应该适用于任何文件。尝试更多文件并看看会发生什么。只是要小心不要破坏重要文件。
警告!
你看到我用echo
制作文件和cat
显示文件的技巧了吗?你可以在附录 A“命令行速成课程”中学习如何做到这一点。
学习练习
-
这个脚本真的很烦人。在复制之前没有必要询问你,而且在屏幕上打印出太多内容。尝试通过删除功能使脚本更加友好易用。
-
看看你能把脚本做得多短。我可以让这一行很长。
-
注意在“你应该看到的内容”末尾我使用了一个叫做
cat
的东西?这是一个“连接”文件的旧命令,但主要是一个将文件打印到屏幕的简单方法。输入man cat
来了解它。 -
找出为什么你需要在代码中写
out_file.close()
。 -
去了解一下 Python 的
import
语句,并开始使用python3
尝试一下。尝试导入一些东西,看看你是否能做对。如果做不对也没关系。 -
尝试将这段代码转换为一个
ex17.py
脚本,你可以再次从终端/PowerShell 运行。如果你已经厌倦了 Jupyter 的文本编辑器,那么可以查看*First Steps*部分提到的编辑器。
常见学生问题
为什么 'w'
要加引号? 那是一个字符串。你已经使用字符串一段时间了。确保你知道什么是字符串。
不可能让这一行变成一行! 那个;取决于;你;如何;定义;一行;代码。
感觉这个练习很难是正常的吗? 是的,这是完全正常的。直到 Exercise 36,甚至可能在你完成这本书并用 Python 做一些东西之后,编程可能才会“点亮”。每个人都不同,所以继续前进,继续复习你遇到困难的练习,直到理解为止。要有耐心。
len()
函数是做什么的? 它获取你传递给它的字符串的长度,然后将其作为一个数字返回。试着玩一下。
当我试图缩短这个脚本时,在结尾关闭文件时出现错误。你可能做了类似这样的事情,indata = open(from_file).read()
,这意味着当你到达脚本结尾时就不需要再执行in_file.close()
。一旦那一行运行,Python 应该已经关闭了它。
我收到一个 Syntax:EOL while scanning string literal
错误。你忘记用引号正确结束一个字符串。再去看看那一行。
模块 2:编程基础
练习 18:名称、变量、代码、函数
大标题,对吧?我将要向你介绍函数!Dum dum dah!每个程序员都会滔滔不绝地谈论函数以及它们如何工作和做什么,但我会给你一个你现在可以使用的最简单的解释。
函数有三个作用:
-
它们命名代码片段的方式就像变量命名字符串和数字一样
-
它们接受参数的方式就像 Python 脚本在练习 13 中接受
argv
-
使用 1 和 2,它们让你制作自己的“迷你脚本”或“微型命令”
你可以像这样在 Python 中使用def
来创建一个空函数:
列表 18.1: ex18_demo.py
1 def do_nothing():
2 pass
这创建了函数,但pass
关键字告诉 Python 这个函数是空的。要使函数执行某些操作,你需要在def
行下添加函数的代码,但要缩进四个空格:
列表 18.2: ex18_demo.py
1 def do_something():
2 print("I did something!")
这实际上将代码print("I did something!")
分配给名称do_something
,这样你以后可以再次在代码中使用它,类似于其他变量。使用你定义的函数是如何“运行”它或“调用”它的:
列表 18.3: ex18_demo.py
1 def do_something():
2 print("I did something!")
3
4 # now we can call it by its name
5 do_something()
当底部的do_something()
运行时,Python 执行以下操作:
-
在 Python 的内存中找到
do_something
函数 -
看到你用
()
调用它 -
跳转到
def do_something()
行的位置 -
运行
def
下的代码行,这里是一行:print("I did
-
[rcurvearrowse]
something!"
当def
下的代码完成时,Python 退出函数并跳回到你调用它的位置 -
然后它继续,这在这种情况下是代码的结尾
对于这个练习,你只需要了解一个概念,那就是函数的“参数”:
列表 18.4: ex18_demo.py
1 def do_more_things(a, b):
2 print("A IS", a, "B IS", b)
3
4 do_more_things("hello", 1)
在这种情况下,我有两个参数(也称为“参数”)传递给do_more_things
函数:a
和b
。当我使用do_more_things("hello", 1)
调用这个函数时,Python 临时赋值a="hello"
和b=1
,然后调用函数。这意味着,在函数内部a
和b
将具有这些值,并且当函数退出时它们将消失。这有点像这样:
列表 18.5: ex18_demo.py
1 def do_more_things(a, b):
2 a = "hello"
3 b = 1
4 print("A IS", a, "B IS", b)
请记住这并不完全准确,因为如果你用不同的参数调用do_more_things
,a
和b
会不同。这只是一个例子,一次你用do_more_things ("hello", 1)
调用它。
练习代码
现在花点时间在 Jupyter 中玩耍,创建自己的函数并在尝试这段代码之前调用它们。确保你理解代码如何跳转到函数,然后再跳回来。然后我会让你创建四个不同的函数,然后我会展示它们之间的关系:
列表 18.6: ex18.py
1 # this one is like your scripts with argv
2 def print_two(*args):
3 arg1, arg2 = args
4 print(f"arg1: {arg1}, arg2: {arg2}")
5
6 # ok, that *args is actually pointless, we can just do this
7 def print_two_again(arg1, arg2):
8 print(f"arg1: {arg1}, arg2: {arg2}")
9
10 # this just takes one argument
11 def print_one(arg1):
12 print(f"arg1: {arg1}")
13
14 # this one takes no arguments
15 def print_none():
16 print("I got nothin'.")
17
18
19 print_two("Zed","Shaw")
20 print_two_again("Zed","Shaw")
21 print_one("First!")
22 print_none()
让我们分解第一个函数print_two
,这与你从制作脚本中已经了解的内容最相似:
-
首先,我们告诉 Python 我们要使用
def
来制作一个函数,其中def
代表“定义”。 -
在与
def
相同的行上,我们给函数命名。在这种情况下,我们只是称之为“print_two”,但也可以是“peanuts”。这不重要,除非你的函数应该有一个简短的名称,说明它的作用。 -
然后我们告诉它我们想要
*args
(星号参数),这很像你的argv
参数,但用于函数。这必须放在()
括号内才能起作用。 -
然后我们以
:
(冒号)结束这一行并开始缩进。 -
冒号之后,所有缩进四个空格的行都将与此名称
print_two
相关联。我们的第一个缩进行是一个解压参数的行,与您的脚本相同。 -
为了演示它的工作原理,我们打印出这些参数,就像在脚本中一样。
print_two
的问题在于这不是制作函数的最简单方法。在 Python 中,我们可以跳过整个解压参数的过程,直接在()
内部使用我们想要的名称。这就是print_two_again
的作用。
在那之后,你有一个在print_one
中接受一个参数的函数示例。
最后,你有一个没有参数的函数print_none
。
警告!
这非常重要。如果现在这还不太明白,不要灰心。我们将做一些练习,将函数与你的脚本链接起来,并向你展示如何制作更多函数。现在,当我说“函数”时,只需继续思考“小型脚本”,并继续尝试。
你应该看到的内容
如果你运行ex18.py
,你应该看到:
1 arg1: Zed, arg2: Shaw
2 arg1: Zed, arg2: Shaw
3 arg1: First!
4 I got nothin'.
立即你就能看到函数是如何工作的。注意你使用函数的方式就像你使用exists
、open
和其他“命令”一样。事实上,我一直在欺骗你,因为在 Python 中,这些“命令”只是函数。这意味着你可以制作自己的命令并在脚本中使用它们。
学习练习
为后续练习创建一个函数清单。将这些检查写在一张索引卡上,并在完成其余练习时或直到你觉得不再需要索引卡时保留在身边:
-
你是否以
def
开始函数定义? -
你的函数名称只包含字符和
_
(下划线)字符吗? -
你是否在函数名称后面放置了
(
(开括号)? -
你是否在
(
(开括号)后面用逗号分隔放置了参数? -
你是否使每个参数都是唯一的(即没有重复的名称)?
-
你是否在参数后面放置了
):
(一个闭括号和一个冒号)? -
你是否将所有想要放在函数中的代码都缩进了四个空格?不多也不少。
-
你是否通过取消缩进(我们称之为“去缩进”)来“结束”函数?
当你运行(“使用”或“调用”)一个函数时,请检查以下事项:
-
你是否通过键入函数名称来调用/使用/运行此函数?
-
你是否在名称后面放置了
(
字符以运行它? -
你是否将想要的值放在括号内,用逗号分隔?
-
你是否以
)
字符结束了函数调用?
在剩下的课程中使用这两个检查表,直到你不再需要它们为止。
最后,对自己重复几次:
1 "To 'run,' 'call,' or 'use' a function all mean the same thing."
常见学生问题
函数名允许使用什么? 与变量名相同。任何不以数字开头且由字母、数字和下划线组成的内容都可以。
在 *args
中的 *
是做什么的? 这告诉 Python 获取函数的所有参数,然后将它们作为列表放入args
中。就像你一直在使用的argv
,但用于函数。除非特别需要,通常不会经常使用。
这感觉真的很无聊和单调。这是好事。这意味着你开始擅长输入代码并理解它的作用。为了让它不那么无聊,把我告诉你要输入的所有内容都故意打破。