练习 13-15 Learn Python 3 The Hard
练习 13 参数,解包,变量
在这个练习中我们将会再涉及一种 input
方法,你可以用这种方法把变量传给一个脚本(也就是你的 .py
文件)。你知道如何运行 ex13.py
吧?输入 python3.6 ex13.py
就行(Windows 下输入 python ex13.py
)。这句命令的 ex13.py 就叫做参数(argument)。我们现在要做的就是写一个也接受参数的脚本。
输入这个程序,然后我会详细解释:
ex13.py
1 from sys import argv
2 # read the WYSS 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)
第一行我们进行了 “import”(导入),这能让你把 Python 功能库中的功能(features)添加到你的脚本中。Python 会问你你想用什么,而不是一次把所有的功能都给你。它会让你的程序很小,但是它同时也可以为其它阅读你代码的程序员提供参考。
这个 argv
是 “argument variable” ,一个在编程语言中非常标准的名字,你会在其它很多的语言中看到它的使用。当你运行 Python 脚本的时候,这个变量(variable)保存了你传给 Python 脚本的参数(argument)。在这个练习中,你会做更多相关的练习,看看会发生什么。
第三行“解包”(unpacks)了 argv
,而不是保留所有的参数,它分成了四个变量:script
, first
, second
, 以及 third
。这可能看起来很奇怪,但是“解包”这个词可能是对这个操作的最好定义,就好像在说:“把 argv 里面的东西解包,然后按顺序分配给从左到右每一个变量。最后就像平常一样把它们打印出来即可。
等等!Features 还有另一个名字
我在这儿把它们叫做 features (就是你导入进来让 python 做更多事情的东西),但是很少有人叫它们 features。我用这个名字只是因为我想让你在专业术语之外思考它们的真正含义。不过在你继续学习之前,你需要知道它们真正的名字:modules (模块)。
从现在开始我们会把这些 features 说成导入模块,比如,“你想导入 sys
模块”。
它们还被有些程序员叫做“libraries”(库),但是我们就用模块这个名字吧。
你会看到
警告! |
---|
注意!你之前一直直接运行 python 脚本,不用输入命令行参数。如果你只输入 python3.6 ex13.py 你就错了!注意看我是怎么操作的,这在任何有 argv 的地方都会用到。 |
像这样运行这个程序,前面是你要传递的命令行参数:
练习 13 结果
$ python3.6 ex13.py first 2nd 3rd
The script is called: ex13.py
Your first variable is: first
Your second variable is: 2nd
Your third variable is: 3rd
当你做一些不同参数的运行时,你会看到:
$ python3.6 ex13.py stuff things that
The script is called: ex13.py
Your first variable is: stuff
Your second variable is: things
Your third variable is: that
$
$ python3.6 ex13.py apple orange grapefruit
The script is called: ex13.py
Your first variable is: apple
Your second variable is: orange
Your third variable is: grapefruit
事实上你还可以把 first
,2nd
,3rd
替换成任何你想替换的东西。如果你没有正确运行,你会收到这样的报错:
$ python3.6 ex13.py first 2nd
Traceback (most recent call last):
File "ex13.py", line 3, in <module>
script, first, second, third = argv
ValueError: not enough values to unpack (expected 4, got 3)
这种情况一般是当你运行脚本的时候没有在命令行放足够的变量(在本例中只有 first
、2nd
)。注意当我运行的时候只给出 first
、2nd
,就会出现错误说“需要三个以上的值来解包”,这就是告诉你,你没有给到足够多的参数。”
附加练习
- 试着给你的脚本三个以内的参数,看看你会收到什么样的报错,你是否能解释它。
- 写一个参数少的脚本和一个参数多的脚本,给未解包的变量起个合适的名字。
- 把
input
和argv
结合起来创建一个脚本,从用户那里获取更多input
。别想得太难,就用argv
来获取一些东西,再用input
从用户那里获取一些东西。- 记住模块给我们一些特征,记住它叫模块(modules),我们之后会用到。
常见问题
当我运行的时候我收到了 ValueError: need more than 1 value to unpack.
还记得我说过,学习编程的一项重要技能就是注意细节。如果你看了“你会看到”那部分,你就会看到我是如何在命令行上运行有参数的脚本的,你应该准确按照我做的来。
argv
和 input()
之间的区别是什么? 区别取决于用户在哪被要求输入,如果是在命令行,就用 argv。如果你想让它们在程序已经运行的情况下用键盘输入,那就用 input()
。
命令行参数是字符串吗?是的,它们是以字符串的形式进来的,即使你在命令行输入的是数字。你可以用 int()
把它们转化成数值,就像 int(input())
。
**你如何使用用命令行?”你应该已经学过命令行的使用了,现在应该用得很 6 了。但是如果你还没有学,先去附录 A 学习命令行速成课程。
我不知道怎么把 argv
和 input()
结合在一起。 别把它想得太难。就在脚本最后加两行,用 input()
获取一些东西,再打印出来。然后试着用更多方式在同一个脚本中使用这两样东西。
为什么我不能这样用:input('? ') = x
? 因为它写反了,按我的要求写,就能运行。
练习 14 提示和传递
让我们来做一个把 argv
和 input
结合在一起的练习来问用户一些特别的问题。这些问题会在你学习下一个练习中阅读和写文件的时候用到。在这个练习中我们会用一种不同的方式使用 input
,就是让它打印出一个简单的 >
提示符。这有点像 Zork 或者 Adventure 这两款游戏。
ex14.py
1 from sys import argv
2
3 script, user_name = argv
4 prompt = '> '
5
6 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
而不是一遍遍地输入它们。现在如果我们想把提示符变成别的东西,只要修改一个地方,然后重新运行脚本即可,非常方便。
你会看到
当你运行脚本的时候,记住一定要把你的名字赋给这个脚本,让 argv
接收到你的名字。
练习 14 结果
$ python3.6 ex14.py zed
Hi zed, I'm the ex14.py script.
I'd like to ask you a few questions.
Do you like me zed?
> Yes
Where do you live zed?
> San Francisco
What kind of computer do you have?
> Tandy 1000
Alright, so you said Yes about liking me.
You live in San Francisco. Not sure where that is.
And you have a Tandy 1000 computer. Nice.
附加练习
- 查查看 Zork 和 Adventure 游戏是什么,找来玩玩。
- 把
prompt
变量改成别的东西。- 在你的脚本里再加一个参数,就像之前练习中
first, second = argv
一样。- 确定你理解了我是如何在最后一行把
"""
多行格式字符(style multiline string)和{}
格式激活器(format activator)结合起来的。
常见问题
我运行脚本的时候收到了 SyntaxError: invalid syntax
。我再说一次,你得在命令行里运行它,而不是在 python 里。如果你输入 python3.6
,然后再输入 python3.6 ex14.py Zed
,就会无法运行,因为你是在 python 里面运行 python。关掉窗口,然后只输入 python3.6 ex14.py Zed
。
你说的“改变提示符”是什么意思?我不太理解。看到这个变量 prompt = '>'
了吗?改变它的值。你知道的,它只是一个字符串,你已经做了 13 个练习来创建它们了,所以好好想想,把它弄明白。
我收到了报错信息:ValueError: need more than 1 value to unpack.
我前面说过,你需要看看“你会看到”那部分然后复制我的做法。这儿也一样,注意我是如何输入命令行的,以及我为什么有一个命令行参数。
我如何从 IDLE 来运行这些?不要用 IDLE。
我能在 prompt 变量外面用双引号吗?你完全可以,试试吧。
你有一台 Tandy computer?是的,在我很小的时候。
我运行的时候收到了报错信息:NameError: name 'prompt' is not defined 。 你要么把 prompt
变量拼写错了,要么把那行漏掉了。回过头去,从下到上比较每一行代码。你一旦遇到这种报错,就说明你拼写错误或者忘了创建变量。
练习 15 阅读文件
你已经知道如何用 input
或者 argv
来获取用户的输入了。现在你将学习如何阅读文件。你需要好好做这个练习,才能理解发生了什么,记住要仔细输入和检查。对文件进行操作很容易把文件删掉,所以你要千万小心。
在这个练习中你要写两个文件。一个是通常你要运行的 ex15.py
,一个是叫做 ex15_sample.txt
的文本文件。以下是文本文件中要输入的内容:
This is stuff I typed into a file.
It is really cool stuff.
Lots and lots of fun to have in here.
我们要做的就是在我们的脚本中打开这个文件并把它打印出来。然而,我们不想只是简单粗暴(hard coding)地把 ex15_sample.txt
这个文件名输入进去,hard coding 的意思是把一些应该从用户那里获取的信息直接放到源代码里。这样不好,因为我们随后会需要它载入别的文件。解决方法是用 argv
或者 input
来问用户应该打开哪个文件,而不是 hard coding 文件名。
ex15.py
1 from sys import argv
2
3 script, filename = argv
4
5 txt = open(filename)
6
7 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
然后阅读说明。看见了吧,就像你自己的脚本和输入,它用了一个参数(parameter)然后返回了一个值,你可以把它赋给你自己的变量。你只是打开了一个文件。
第 7 行打印了一些信息,第 8 行就有一些新东西了。我们对 txt 用了一个叫做 read.
的函数,你从 open
那里得到的是一个文件,而且你还可以通过 . 命令名,以及参数,来给它一个命令,就像用 open
和 input
那样。区别是,txt.(read)
是说:txt
,执行不带参数的 read
命令!
剩下的部分基本上类似,但是我们会把分析留到附加练习里。
你会看到
警告! |
---|
注意!你一直通过输入文件名来运行脚本,但是你要用 argv 加上参数来运行。看看下面例子的第一行,你会看我是通过输入 python ex15.py ex15_sample.txt 来运行它的。 ex15.py 后面的内容就是你要输入的参数,如果你漏掉了,就会收到报错信息!所以千万要注意! |
我创建了一个叫做 ex15_sample.txt
的文件来运行我的脚本。
练习 15 结果
$ python3.6 ex15.py ex15_sample.txt
Here's your file ex15_sample.txt:
This is stuff I typed into a file.
It is really cool stuff.
Lots and lots of fun to have in here.
Type the filename again:
> ex15_sample.txt
This is stuff I typed into a file.
It is really cool stuff.
Lots and lots of fun to have in here.
附加练习
这部分可能比较难,在你往下进行之前,确保你尽力去做这个附加练习。
- 在每行上面添加注释解释其含义。
- 如果你不确定,上网搜,或者问别人,比如你不知道 open 的用法,直接搜
python3.6 open
即可。- 我在这儿用的是“命令”(command)这个词,不过,它也叫“函数”(function)或者“方法”(method)。你会在本书后面学到 functions 和 methods。
- 把第 10-15 行删掉(或者用别的方法使其失效)然后再运行脚本。
- 只用 input 来试试运行这个脚本。为什么要获取文件名的话一种方法比另一种方法更好?
- 开启 python3.6 shell,然后就像这个程序中一样从提示界面用
open
。注意你是如何从 python3.6 里面打开文件并运行read
的?- 在你的脚本中对
txt
调用close()
以及txt_again
变量。当你对它们完成操作后关掉文件是非常重要的。
常见问题
txt = open(filename)
会返回文件的内容吗? 不会。它其实是创建了一个叫做“文件对象”(file object)的东西。你可以把它想象成曾经的 DVD 播放器,你可以在里面移动然后“读取”它们。但是 DVD 播放器不是 DVD 本身,就像文件对象也不是文件本身一样。
我无法像你附加练习 7 中说的那样在 Terminal/PowerShell 里输入代码。 首先,在命令行输入 python3.6
然后敲回车。现在你已经在 python3.6 里面了。然后你可以输入代码,python 就会运行一些。试着这样玩玩,然后输入 quit()
并回车,退出。
为什么打开文件两次不会收到报错?
Python 不会限制你只能打开一次文件,事实上有时候确实需要打开多次。
from sys import argv
是什么意思?现在你只需要明白 sys
是一个包(package),这个短语是说从那个包里获取 argv
功能(feature)。你会在后面深入学习这块内容。
我把脚本文件名这样放进去:ex15_sample.txt = argv
, 但是无法运行。 你不能这样做。严格按照我的代码来,然后用同样的方法在命令行运行它。你不用把文件名放进去,你得让 python 自己放。