笨办法学 Python3 第五版(预览)(二)(2)https://developer.aliyun.com/article/1483431
通过以下方式创建数据对象:
- 用
{
(大括号)打开它 - 写入键,这里是一个字符串,但可以是数字,或几乎任何东西
- 写入一个
:
(冒号) - 写入值,可以是 Python 中有效的任何内容
一旦你这样做,你可以像这样访问这封 Python 电子邮件:
1 email["From"] 2 'j.smith@example.com' 3 4 email["To"] 5 'zed.shaw@example.com' 6 7 email["Subject"] 8 'I HAVE AN AMAZING INVESTMENT FOR YOU!!!'
你会注意到这与你访问模块中的变量和函数的方式非常相似,你需要require
。使用.
(点)是你可以访问 Python 中许多数据结构部分的主要方式。你也可以使用前一个练习中的[]
语法来访问这些数据:
1 email['To'] 2 'zed.shaw@example.com' 3 4 email['From'] 5 'j.smith@example.com'
与list
索引的唯一区别是你使用字符串(‘From’)而不是整数。但是,如果你愿意,你也可以使用整数作为键(后面会详细介绍)。
将列表与数据对象结合
编程中的一个常见主题是将组件组合以获得令人惊讶的结果。有时惊喜是崩溃或错误。其他时候,惊喜是一种新颖的完成某项任务的方式。无论如何,当你进行新颖的组合时发生了什么并不是真正的惊喜或秘密。对于你来说可能是惊喜的,但语言规范中通常会有一个解释(即使这个原因绝对愚蠢)。你的计算机中没有魔法,只有你不理解的复杂性。
将数据对象放入lists
中的一个很好的例子。你可以这样做:
1 messages = [ 2 {to: 'Sun', from: 'Moon', message: 'Hi!'}, 3 {to: 'Moon', from: 'Sun', message: 'What do you want Sun?'}, 4 {to: 'Sun', from: 'Moon', message: "I'm awake!"}, 5 {to: 'Moon', from: 'Sun', message: 'I can see that Sun.'} 6 ];
一旦我这样做了,我现在可以使用list
语法来访问数据对象,就像这样:
1 messages[0].to 2 'Sun' 3 4 messages[0].from 5 'Moon' 6 messages[0].message 7 'Hi!' 8 9 messages[1]['to'] 10 'Moon' 11 12 messages[1]['from'] 13 'Sun' 14 15 messages[1]['message'] 16 'What do you want Sun?'
注意我在messages[0]
后面立即使用.
(点)语法的方式?再次尝试结合功能,看看它们是否有效,如果有效,找出原因,因为总会有一个原因(即使它很愚蠢)。
代码
现在,你将重复使用lists
的练习,并写出我精心制作的三个数据对象。然后,你将把它们输入到 Python 中,并尝试访问我给你的数据。记得尝试在脑海中完成这个任务,然后用 Python 检查你的工作。你还应该练习对list
和dict
结构进行这样的操作,直到你有信心可以访问内容。你会意识到数据是相同的,只是被重新构造了。
列表 24.1: ex24.py
1 fruit = [ 2 {kind: 'Apples', count: 12, rating: 'AAA'}, 3 {kind: 'Oranges', count: 1, rating: 'B'}, 4 {kind: 'Pears', count: 2, rating: 'A'}, 5 {kind: 'Grapes', count: 14, rating: 'UR'} 6 ]; 7 8 cars = [ 9 {type: 'Cadillac', color: 'Black', size: 'Big', miles: 34500}, 10 {type: 'Corvette', color: 'Red', size: 'Little', miles: 1000000}, 11 {type: 'Ford', color: 'Blue', size: 'Medium', miles: 1234}, 12 {type: 'BMW', color: 'White', size: 'Baby', miles: 7890} 13 ]; 14 15 languages = [ 16 {name: 'Python', speed: 'Slow', opinion: ['Terrible', 'Mush']}, 17 {name: 'JavaScript', speed: 'Moderate', opinion: ['Alright', 'Bizarre' ↪] ]}, 18 {name: 'Perl6', speed: 'Moderate', opinion: ['Fun', 'Weird']}, 19 {name: 'C', speed: 'Fast', opinion: ['Annoying', 'Dangerous']}, 20 {name: 'Forth', speed: 'Fast', opinion: ['Fun', 'Difficult']}, 21 ];
你应该看到的结果
请记住,你在这里进行了一些复杂的数据访问操作,所以要慢慢来。你必须遍历你分配给模块的data
变量,然后访问lists
,接着是数据对象,有时还有另一个list
。
挑战
我会给你完全相同的数据元素集,你需要找出获取这些信息所需的索引。例如,如果我告诉你fruit 'AAA'
,那么你的答案是fruit[0].rating
。你应该试着在脑海中通过查看代码来做到这一点,然后在python
shell 中测试你的猜测。
水果挑战
你需要从fruit
变量中取出所有这些元素:
- 12
- ‘AAA’
- 2
- ‘橙子’
- ‘葡萄’
- 14
- ‘苹果’
汽车挑战
你需要从cars
变量中取出所有这些元素:
- ‘大的’
- ‘红色的’
- 1234
- ‘白色的’
- 7890
- ‘黑色的’
- 34500
- ‘蓝色的’
语言挑战
你需要从languages
变量中取出所有这些元素:
- ‘慢的’
- ‘好的’
- ‘危险的’
- ‘快的’
- ‘困难的’
- ‘有趣的’
- ‘烦人的’
- ‘奇怪的’
- ‘适度的’
最终挑战
你的最终挑战是编写出写出与练习 23 中相同歌词的 Python 代码。再次慢慢来,试着在脑海中完成再看看你是否做对了。如果你做错了,花时间理解为什么错了。作为对比,我在脑海中一次性写出了歌词,没有出错。我也比你有更多经验,所以你可能会犯一些错误,那也没关系。
你不知道这些是歌词吗?这是一首由王子演唱的歌曲叫做“Little Red Corvette”。在继续阅读本书之前,你现在被命令听 10 首王子的歌曲,否则我们就不能再做朋友了。再也不能!
练习 25:字典和函数
在这个练习中,我们将通过将函数与dict
结合起来做一些有趣的事情。这个练习的目的是确认你可以在 Python 中组合不同的东西。组合是编程的关键方面,你会发现许多“复杂”的概念实际上只是更简单概念的组合。
第一步:函数名称是变量
为了做好准备,我们首先要确认函数的名称就像其他变量一样。看看这段代码:
1 def print_number(x): 2 print("NUMBER IS", x) 3 4 rename_print = print_number 5 rename_print(100) 6 print_number(100)
如果你运行这段代码,你会发现rename_print
和print_number
做的事情完全相同,这是因为它们是相同的。函数的名称与变量的名称相同,你可以将名称重新分配给另一个变量。这就像这样做一样:
1 x = 10 2 y = x
玩弄这个,直到你明白。创建自己的函数,然后将它们分配给新名称,直到你理解这个概念。
第二步:带有变量的字典
这可能很明显,但以防你还没有建立联系,你可以将一个变量放入dict
中:
1 color = "Red" 2 3 corvette = { 4 "color": color 5 } 6 7 print("LITTLE", corvette["color"], "CORVETTE")
接下来的拼图部分是有意义的,因为你可以将数字和字符串等值放入dict
中。你也可以将这些相同的值分配给变量,因此将它们组合起来并将变量放入dict
中是有意义的。
第三步:带有函数的字典
你应该看到这是怎么回事了,但现在我们可以将这些概念结合起来,将一个函数放入dict
中:
1 def run(): 2 print("VROOM") 3 4 corvette = { 5 "color": "Red", 6 "run": run 7 } 8 9 print("My", corvette["color"], "can go") 10 corvette["run"]()
我从前面的color
变量中取出,并将其直接放入corvette
的dict
中。然后我创建了一个名为run
的函数,并将其放入corvette
中。最棘手的部分是最后一行corvette ["run"]()
,但看看你是否可以根据你所知道的来弄清楚它。在继续之前,花些时间写出这行代码正在做什么的描述。
第四步:解密最后一行
解密最后一行corvette["run"]()
的技巧是将其分解成每个部分。人们对这样的代码行感到困惑的原因是他们看到了一个单一的东西,“运行 corvette”。事实上,这行代码由许多东西组合在一起共同工作。如果我们将其拆分开来,我们可以得到这段代码:
1 # get the run fuction out of the corvette dict 2 myrun = corvette["run"] 3 # run it 4 myrun()
即使这两行并不是整个故事,但这向你展示了这至少是一行上的两个操作:使用["run"]
获取函数,然后使用()
运行函数。为了进一步分解这个,我们可以写成:
corvette
告诉 Python 加载dict
[
告诉 Python 开始索引到corvette
"run"
告诉 Python 使用"run"
作为键来搜索dict
]
告诉 Python 你已经完成索引,它应该完成索引- Python 然后返回与键
"run"
匹配的corvette
内容,这是之前的run()
函数 - Python 现在有了
run
函数,所以()
告诉 Python 像调用任何其他函数一样调用它
花些时间理解这是如何工作的,并在corvette
上编写自己的函数以使其执行更多操作。
学习练习
现在你有一段控制汽车的好代码。在这个练习中,你将创建一个新的函数,创建任何汽车。你的创建函数应满足以下要求:
- 它应接受参数来设置颜色、速度或其他你的汽车可以做的任何事情。
- 它应创建一个包含正确设置并已包含你创建的所有函数的
dict
。 - 它应返回这个
dict
,这样人们可以将结果分配给任何他们想要的东西,并以后使用。 - 它应该被编写成这样,以便某人可以创建任意数量的不同汽车,每个他们制造的汽车都是独立的。
- 你的代码应通过改变几辆不同汽车的设置来测试#4,然后确认它们没有改变其他汽车的设置。
这个挑战不同,因为我会在后面的练习中向你展示挑战的答案。如果你在这个挑战中遇到困难,那么暂时搁置它,继续前进。你很快会再次看到它。
练习 26:字典和模块
在这个练习中,你将探索dict
如何与模块一起工作。每当你使用import
将“功能”添加到你自己的 Python 源代码时,你都在使用模块。你在练习 17 中使用得最多,所以在开始这个练习之前,最好回顾一下那个练习。
步骤 1: import
的回顾
第一步是回顾import
的工作方式并进一步发展这方面的知识。花点时间将这段代码输入到一个名为ex26.py
的 Python 文件中。你可以在 Jupyter 中通过创建一个文件(左侧,蓝色[+]
按钮)来做到这一点:
列表 26.1: ex26.py
1 name = "Zed" 2 height = 74
创建了这个文件后,你可以用这个导入它:
列表 26.2: ex26_code.py
1 import ex26
这将把ex26.py
的内容带入你的 Jupyter lab 中,这样你就可以像这样访问它们:
列表 26.3: ex26_code.py
1 print("name", ex26.name) 2 print("height", ex26.height)
尽可能多地尝试玩这个。尝试添加新变量并再次导入以查看其工作原理。
步骤 2: 找到__dict__
一旦你理解了import
是将ex26.py
的内容导入到你的 lab 中,你就可以开始像这样调查__dict__
变量:
列表 26.4: ex26_code.py
1 from pprint import pprint 2 3 pprint(ex26.__dict__)
pprint
函数是一个“漂亮打印机”,将以更好的格式打印__dict__
。
使用pprint
,你会突然发现ex26
有一个名为__dict__
的“隐藏”变量,它实际上是一个包含模块中所有内容的dict
。你会在 Python 中的各个地方找到这个__dict__
和许多其他秘密变量。__dict__
的内容包含了许多不是你的代码的东西,但这只是 Python 需要处理模块的东西。
这些变量是如此隐藏,以至于即使顶级专业人员也会忘记它们的存在。许多这样的程序员认为模块与dict
完全不同,而实际上模块使用了__dict__
,这意味着它与dict
相同。唯一的区别是 Python 有一些语法,让你使用.
运算符而不是dict
语法来访问模块,但你仍然可以像访问dict
一样访问内容:
列表 26.5: ex26_code.py
1 print("height is", ex26.height) 2 print("height is also", ex26\. dict ['height'])
对于这两种语法,你会得到相同的输出,但.
模块语法肯定更容易。
步骤 3: 改变__dict__
如果一个模块确实是内部的dict
,那么这意味着改变__dict__
的内容也应该改变模块中的变量。让我们试一试:
列表 26.6: ex26_code.py
1 print(f"I am currently {ex26.height} inches tall.") 2 3 ex26\. dict ['height'] = 1000 4 print(f"I am now {ex26.height} inches tall.") 5 6 ex26.height = 12 7 print(f"Oops, now I'm {ex26\. dict ['height']} inches tall.")
正如你所看到的,当你改变ex26.__dict__['height']
时,变量ex26.height
也会改变,这证明了模块确实是__dict__
。
这意味着.
运算符被转换为__dict__[]
访问操作。我希望你记住这一点,因为很多初学者看到ex26.height
时,他们认为这是一个单独的代码单元。实际上,这实际上是三个或四个单独的操作:
- 找到
ex26
。 - 找到
ex26.__dict__
。 - 使用
"height"
索引到__dict__
。 - 返回该值。
一旦你建立了这种联系,你就会开始理解.
是如何工作的。
学习练习:找到“Dunders”
__dict__
变量通常被称为“双下划线”变量,但程序员们很懒,所以我们只是称它们为“dunder 变量”。在学习关于 dunder 变量的最后一步中,你将访问 Python 文档中描述数据模型的部分,其中描述了许多这些 dunder 的用法。
这是一个很大的文档,其写作风格非常枯燥,所以最好的学习方法是搜索__
(双下划线),然后根据其描述找到访问这个变量的方法。例如,你可以尝试在几乎任何地方访问__doc__
:
列表 26.7: ex26_code.py
1 from pprint import pprint 2 print(pprint. doc )
这将为你提供与pprint
函数相关联的一点文档。你可以使用help
函数访问相同的信息:
列表 26.8: ex26_code.py
1 help(pprint)
尝试用你能找到的所有其他 dunder 进行这些实验。你很可能不会直接使用它们,但了解 Python 内部工作原理是很有好处的。
练习 27:编程游戏的五个简单规则
信息
这个练习旨在在你学习下一个练习时定期学习。你应该慢慢来,将其与其他解释混合在一起,直到最终理解。如果在这个练习中迷失了方向,休息一下,然后进行下一个练习。然后,如果在后面的练习中感到困惑,回来学习我在这里描述的细节。一直坚持下去,直到“豁然开朗”。记住,你不会失败,所以继续努力直到理解为止。
如果你玩围棋或国际象棋这样的游戏,你会知道规则相当简单,但它们所启用的游戏却极其复杂。真正好的游戏具有简单规则和复杂互动的独特品质。编程也是一个具有少量简单规则的游戏,这些规则创造了复杂的互动,在这个练习中,我们将学习这些规则是什么。
在我们做这个之前,我需要强调的是,当你编写代码时,你很可能不会直接使用这些规则。有些语言确实直接利用这些规则,你的 CPU 也使用它们,但在日常编程中你很少会使用它们。如果是这样,那么为什么要学习这些规则呢?
因为这些规则无处不在,理解它们将帮助你理解你编写的代码。当代码出错时,它将帮助你调试代码。如果你想知道代码是如何工作的,你将能够将其“分解”到基本规则,真正看到它是如何工作的。这些规则就像是一个秘密的代码。完全是故意的双关语。
我还要警告你不要期望立即完全理解这一点。把这个练习看作是为本模块中其余练习做准备。你应该深入研究这个练习,当遇到困难时,继续进行下一个练习作为休息。你应该在这个练习和下一个练习之间来回跳动,直到概念“豁然开朗”并开始变得有意义。你也应该尽可能深入地研究这些规则,但不要在这里卡住。挣扎几天,继续前进,回来,继续努力。只要你继续努力,你实际上不可能“失败”。
规则 1:一切都是一系列指令
所有程序都是一系列指令,告诉计算机做某事。当你输入这样的代码时,你已经看到 Python 在做这个了:
1 x = 10 2 y = 20 3 z = x + y
这段代码从第 1 行开始,到第 2 行,依此类推直到结束。这是一系列指令,但在 Python 中,这三行被转换为另一系列指令,看起来像这样:
1 LOAD_CONST 0 (10) # load the number 10 2 STORE_NAME 0 (x) # store that in x 3 4 LOAD_CONST 1 (20) # load the number 20 5 STORE_NAME 1 (y) # store that in y 6 7 LOAD_NAME 0 (x) # loads x (which is 10) 8 LOAD_NAME 1 (y) # loads y (which is 20) 9 BINARY_ADD # adds those 10 STORE_NAME 2 (z) # store the result in z
这看起来与 Python 版本完全不同,但我敢打赌你可能能够猜出这一系列指令在做什么。我已经添加了注释来解释每个指令,你应该能够将其与之前的 Python 代码联系起来。
我不是在开玩笑。现在花点时间将 Python 代码的每一行与这个“字节码”的行联系起来。使用我提供的注释,我相信你可以弄清楚,这样做可能会在你的脑海中点亮一盏灯,让你更好地理解 Python 代码。
不需要记住这些指令,甚至不需要理解每一条指令。你应该意识到的是,你的 Python 代码被翻译成了一系列简单的指令,告诉计算机做什么。这个指令序列被称为“字节码”,因为它通常以一系列计算机理解的数字的形式存储在文件中。你在上面看到的输出通常被称为“汇编语言”,因为它是这些字节的人类“可读”(勉强)版本。
这些简单的指令从顶部开始处理,一次执行一个小操作,当程序退出时到达末尾。这就像你的 Python 代码,但语法更简单,是INSTRUCTION OPTIONS
的形式。另一种看待这个问题的方式是,x = 10
的每个部分可能会在这个“字节码”中成为自己的指令。
这是《编码游戏》的第一条规则:你写的每一行最终都会成为一系列字节,作为计算机的指令输入,告诉计算机应该做什么。
我怎样才能得到这个输出?
要自己得到这个输出,你可以使用一个名为[dis](https://docs.python.org/3/library/dis.xhtml)
的模块,它代表“disassemble”。这种代码传统上被称为“字节码”或“汇编语言”,所以dis
的意思是“反汇编”。要使用dis
,你可以导入它并像这样使用dis()
函数:
1 # import the dis function 2 from dis import dis 3 4 # pass code to dis() as a string 5 dis(''' 6 x = 10 7 y = 20 8 z = x + y 9 ''')
笨办法学 Python3 第五版(预览)(二)(4)https://developer.aliyun.com/article/1483437