Python 项目入门指南(二)
四、列表和循环
在这一周里,我将介绍一种叫做“列表的新数据类型和一种叫做“循环的新概念列表将赋予我们存储大型数据集的能力,而循环将允许我们重新运行部分代码。
这两个主题是一起介绍的,因为列表很适合循环。尽管列表是 Python 中最重要的数据类型之一,但在介绍它们之前,我们需要理解数据类型和分支语句的基础。到这个周末,我们将有必要的工具来建立一个小规模的刽子手游戏。我们将使用我们在前几周和本周学到的所有概念。
通过应用和重复,每次介绍一个概念时,你都能进一步理解它。如果你还没有一个概念,重要的是要坚持下去,不要停留在单一的课程上。
概述
-
了解列表数据类型
-
如何以及为什么使用 for 循环
-
如何以及为什么使用 while 循环
-
了解如何使用列表
-
一起创造刽子手
挑战问题
想象你是一个大城市的市长。对于这个例子,让我们假设主要城市是马萨诸塞州的波士顿。你刚刚收到警报,你需要撤离这座城市。你首先做什么?
星期一:列表
今天我们将介绍 Python 中最重要的数据类型之一,列表。在其他语言中,它们也被称为“数组,具有类似的特征。这是你学习的第一个数据收集。在接下来的几周里,我们将看到其他数据收集类型。
为了继续今天的内容,让我们从“ python_bootcamp ”文件夹中打开 Jupyter 笔记本。打开后,创建一个新文件,并将其重命名为“ Week_04 接下来,制作第一个标题为:“列出了的单元格我们将开始在那间牢房下面工作。
什么是列表?
一个列表是 Python 中的一个数据结构,是元素的可变、有序序列。可变意味着你可以改变里面的项目,而有序序列是指索引位置。列表中的第一个元素总是位于索引 0 。列表中的每个元素或值被称为一个项目。正如字符串被定义为引号之间的字符一样,列表是通过在方括号 [ ] 之间使用不同的数据类型来定义的。同样,像字符串一样,列表中的每一项都被分配了一个索引或位置,用于该项在内存中的保存位置。列表也被称为数据集合。数据集合只是可以存储多项的数据类型。在后面的章节中,我们会看到其他的数据集合,比如字典和元组。
声明数字列表
对于我们的第一个列表,我们将创建一个只填充数字的列表。定义一个列表就像任何其他数据类型一样;运算符的左边是变量的名称,右边是值。这里的区别在于,值是一组在方括号中声明的项。这对于存储类似的信息很有用,因为您可以轻松地传递一个存储多个元素的变量名。为了分隔列表中的每一项,我们简单地使用逗号。让我们试试:
# declaring a list of numbers
nums = [5, 10, 15.2, 20]
print(nums)
去查查那个手机。你会得到**【5,10,15.2,20】**的输出。当输出一个列表时,它包括括号。这个当前列表由三个整数和一个浮点数组成。
访问列表中的元素
现在我们知道了如何定义一个列表,我们需要采取下一步,了解如何访问列表中的条目。为了访问列表中的特定元素,您使用了一个索引。当我们声明列表变量时,每一项都有一个索引。请记住,Python 中的索引从零开始,用括号括起来。第 2 周的星期三也包括索引:
# accessing elements within a list
print( nums[1] ) # will output the value at index 1 = 10
num = nums[2] # saves index value 2 into num
print(num) # prints value assigned to num
去查查那个手机。这里我们将得到两个值输出, 10 和 15.2 。输出第一个值是因为我们正在访问我们的 nums 列表中的索引位置 1,其中存储了一个整数 10。在我们创建了一个名为 num 的新变量之后,第二个值被打印出来,这个变量被设置为存储在我们的 nums 列表中索引 2 处的值。
声明混合数据类型列表
列表可以保存任何数据类型,甚至其他列表。让我们来看看几种数据类型的例子:
# declaring a list of mixed data types
num = 4.3
data = [num, "word", True] # the power of data collection
print(data)
去查查那个手机。这会输出**【4.3,'字',真】**。它输出 4.3 作为第一项,因为当定义列表时,它存储的是 num 的值,而不是变量本身。
列表中的列表
让我们变得复杂一点,看看列表如何存储在另一个列表中:
# understanding lists within lists
data = [5, "book", [ 34, "hello" ], True] # lists can hold any type
print(data)
print( data[2] )
去查查那个手机。这将输出 [5,'书',[34,'你好'],True] 和 [34,'你好'] 。第一个输出是整个数据变量的值,它存储了一个整数、一个字符串、一个列表和一个布尔数据类型。第二个输出是存储在我们的数据变量中的列表,它位于索引 2 处,包含一个整数和字符串数据类型。
访问列表中的列表
在最后一个单元格中,我们看到了如何输出存储在数据变量中的列表。现在,我们将看看如何访问内部列表中的项目。要正常访问列表中的条目,我们只需使用括号符号和索引位置。当该项目是另一个列表时,只需在第一组括号后添加第二组括号。让我们先来看一个例子,然后再回过头来看:
# using double bracket notation to access lists within lists
print( data[2][0] ) # will output 34
inner_list = data[2] # inner list will equal [34, 'hello']
print( inner_list[1] ) # will output 'hello'
去查查那个手机。第一个输出将是 34 。这是因为我们的第一个索引位置正在访问数据中的第二个索引,这是一个列表。然后,指定的第二个索引位置正在访问位置 0 处的那个列表中的值,这导致整数 34。第二个输出是**“你好”。我们得到这个结果是因为我们声明了一个变量来存储我们的数据变量的索引 2 处的值,这个变量恰好是一个列表。我们的 inner_list 变量现在等于【34,' hello '】,我们访问索引 1 处的值,它是字符串**“hello”**。为了更好地理解多重索引的工作原理,请查看表格 4-1 。
表 4-1
多重索引值
|索引位置
|
位置值
|
数据类型
|
可以再次索引
| | --- | --- | --- | --- | | Zero | five | 整数 | 不 | | one | “书” | 线 | 是 | | Two | [34,'你好'] | 目录 | 是 | | three | 真实的 | 布尔代数学体系的 | 不 |
请注意,字符串还可以进一步索引。如果您只想打印出“book”中的“b”,您只需简单地写下以下内容:
>>> print( data[ 1 ][ 0 ] ) # will output 'b'
更改列表中的值
当您使用列表时,您需要能够改变列表中项目的值。这就像将一个普通变量重新声明为一个不同的值,除了您首先访问索引:
# changing values in a list through index
data = [5, 10, 15, 20]
print(data)
data[0] = 100 # change the value at index 0 - (5 to 100)
print(data)
去查查那个手机。在我们改变索引 0 处的值之前,它输出**【5,10,15,20】。一旦我们访问了零索引并将其值更改为 100 ,然而,列表最终更改为【100,10,15,20】**。
可变存储
当变量被声明时,赋值被放入内存中的一个位置。这些位置有一个特定的参考 ID。您不经常需要检查变量的 ID,但是出于教育目的,了解存储是如何工作的是有好处的。我们将使用 id() 函数来检查变量在内存中的存储位置:
>>> a = [ 5, 10 ]
>>> print( id(a) ) # large number represents location in memory
当一个列表存储在内存中时,每个条目都有自己的位置。使用索引符号更改该值将会更改存储在该内存块中的值。现在,如果一个变量的值是另一个变量,就像这样:
>>> a = [5, 10]
>>> b = a
更改特定索引处的值将会更改这两个列表的值。让我们看一个例子:
# understanding how lists are stored
a = [5, 10]
b = a
print( "a: { }\t b: { }".format(a, b) )
print( "Location a[0]: { }\t Location b[0]: { }".format( id(a[0]), id(b[0]) ) )
a[0] = 20 # re-declaring the value of a[0] also changes b[0]
print( "a: { }\t b: { }".format(a, b) )
去查查那个手机。我们会得到几个输出。第一个是打印出两个列表变量的值,以显示它们具有相同的值。第二个 print 语句将输出每个列表的第一项在内存中的位置。最后,在我们改变了列表*“a”中第一项的值之后,列表“b”*中的值也会改变。这是因为它们共享相同的内存位置。
复制列表
那么,如何在不改变原始列表的情况下创建一个类似的列表呢?你抄!让我们看看如何:
# using [:] to copy a list
data = [5, 10, 15, 20]
data_copy = data[ : ] # a single colon copies the list
data[0] = 50
print( "data: { }\t data_copy: { }".format(data, data_copy) )
去查查那个手机。这次的输出将导致只有我们的数据变量的第一项被设置为 50 。由于 data_copy 仅仅是列表的一个副本,现在如果我们需要再次使用它,我们可以一直保持原始列表的完整性。
注意
您也可以使用方法。复制()。
周一练习
-
Sports:定义一个字符串列表,其中每个字符串都是一项运动。然后用下面的一行输出每项运动“我喜欢玩{ }”…
-
第一个字符:对于下面的列表,打印出每个项目的第一个字母。(输出应为‘J’,‘A’,‘S’,‘K’)
names = ['约翰','亚伯拉罕','山姆','凯利']
今天是关于我们的第一个数据收集类型,列表。有很多内容要介绍,但是理解如何定义、更改值和复制列表是很重要的。
星期二:循环
今天我们将讨论编程中的一个重要概念,循环。在大多数应用程序中,您需要能够多次运行相同的代码。我们使用循环,而不是多次编写相同的代码行。在 Python 中有两种类型的循环,今天的课程是关于循环的
**为了跟上这一课,让我们从之前的笔记本文件“ Week_04 ”继续,简单地在底部添加一个标有“ For Loops ”的降价单元格
循环如何工作
循环是程序员多次重新运行同一行代码的方式。循环将一直运行,直到满足某个条件。以一个第一人称射击游戏为例,游戏将继续运行,直到要么你赢了,要么你的生命值为零。一旦出现任何一种情况,游戏就结束了。
注意
将你的代码压缩到尽可能少的行总是很重要的,因为这对程序来说更有效率。
不管你是否知道,循环在生活中无处不在。每天我们醒来,去工作,去睡觉,我们知道这是例行公事,但这只是一个循环。我们每天重复同样的过程,直到周末。同样的概念也适用于我们程序中的循环。
编写 For 循环
For 循环主要用于循环一定的次数。以图 4-1 为例,这个语法表明循环将运行五次。让我们进一步分析一下。每个 for 循环都以关键字**“for”开始。然后定义一个临时变量,有时称为计数器或索引。接下来是“关键字中的”,后面是 range 函数(后面会解释)。最后,我们用冒号来结束语句。所有 for 循环都将遵循关键字、变量、关键字、函数和冒号的精确结构。**
图 4-1
For 循环语法
现在我们已经讨论了编写 for 循环的结构,让我们来编写一个:
# writing your first for loop using range
for num in range(5):
print( "Value: { }".format(num) )
去查查那个手机。这将为我们的值输出“ 0,1,2,3,4 ”。这个循环实际上是数到五并打印出每个数字。那么它是如何打印出每个数字的呢?创建 for 循环时,默认情况下,range 函数从零开始,并将零值赋给我们的临时变量 num 。每次循环都是我们所谓的迭代。对于每一次迭代,一旦块中的所有代码都运行了,当前的迭代就结束了,循环从顶部重新开始。除了这次,它增加了 num 的值,默认为 1 。我们的临时变量被赋值为 1 的值,并继续运行 for 循环中的代码行,这只是打印出 num 的值。它将继续这样做,直到我们达到数字 5。为了给你一个每次迭代赋值的概念,参考表 4-2 。
表 4-2
使用 range()为每次迭代分配的值
|循环迭代
|
数字的值
|
输出
| | --- | --- | --- | | one | Zero | 值:0 | | Two | one | 值:1 | | three | Two | 值:2 | | four | three | 值:3 | | five | four | 值:4 |
注意
不输出值 5,因为 range()计数到但不包括
范围( )
范围允许我们从一个数字计数到另一个数字,同时能够定义从哪里开始开始和结束,以及我们增加或减少多少。也就是说,如果我们愿意,我们可以每隔一个数字或者每隔五个数字计算一次。当与 for 循环一起使用时,它使我们能够循环一定的次数。在前面的例子中,我们看到范围 5 打印出五个数字。这是因为范围默认从 0 开始,每次递增 1。让我们看另一个例子:
# providing the start, stop, and step for the range function
for num in range(2, 10, 2):
print( "Value: { }".format(num) ) # will print all evens between 2 and 10
去查查那个手机。这一次,我们指定程序从值 2 开始循环,计数到 10,但增量为 2。我们的值的输出变为“ 2,4,6,8 ”。
按元素循环
当处理可迭代的数据类型时,意味着它们有一个可以循环的元素集合,我们可以用不同的方式编写 for 循环:
# printing all characters in a name using the 'in' keyword
name = "John Smith"
for letter in name:
print( "Value: { }".format(letter) )
去查查那个手机。输出将是每次打印出一个字母。记住,字符串可以被索引,并且是字符或符号的集合,这使得它们是可迭代的。这个 for 循环将遍历每个字符,并在包含该字符/符号的块中运行代码。表 4-3 回顾了该循环的前几次迭代。
表 4-3
在具有范围的字符串上循环的迭代值
|循环迭代
|
信的价值
|
输出
| | --- | --- | --- | | one | J | 值:J | | Two | o | 值:o | | three | h | 值:h | | four | n | 值:n | | five | 空格符号 | 价值: | | six | S | 值:S |
连续语句
现在我们已经看到了循环是如何工作的,让我们来讨论几个可以用于循环的重要语句。第一个是继续语句。一旦 continue 语句被命中,当前迭代将停止并返回到循环的顶部。让我们看一个例子:
# using the continue statement within a foor loop
for num in range(5):
if num == 3:
continue
print(num)
去查查那个手机。输出将导致 0,1,2,4 ,因为只有当 num 等于 3 的值时,才会读取 continue 语句。一旦命中该语句,它将停止当前的迭代,并返回到顶部,继续在下一次迭代中循环。这完全阻止了 continue 下面的代码被解释,所以它不会命中 print 语句。
break 语句
我们可以使用的最重要的语句之一是 break 语句。它允许我们在任何时间点打破循环。让我们看一个例子:
# breaking out of a loop using the 'break' keyword
for num in range(5):
if num == 3:
break
print(num)
去查查那个手机。输出将导致“ 0,1,2 ”,因为当 num 等于 3 时,我们完全打破了循环。一旦断点被读取,循环完全停止,循环内不再运行代码。这对于在满足条件时停止循环非常有用。
注意
如果使用双循环,break 语句将只从该语句所在的循环中断开。也就是说,如果在内部循环中使用 break 语句,它将不会同时跳出两个循环。
Pass 语句
这三个语句的最后一个是 pass。pass 语句只是一个占位符,这样程序就不会中断。让我们看一个例子:
# setting a placeholder using the 'pass' keyword
for i in range(5):
# TODO: add code to print number
pass
去查查那个手机。什么都没发生,但这是件好事。如果你完全去掉 pass 语句,程序将会崩溃,因为块中需要某种代码。
它的存在只是为了让我们不必在循环中写代码。这对设计一个程序很有用。
注意
使用“ TODO 是设置提醒的一般惯例。
星期二练习
-
可被三整除:编写一个 for 循环,打印出从 1 到 100 的所有可被三整除的数字。
-
Only 元音字母:要求用户输入,编写一个 for 循环,输出循环中的所有元音字母。例如:
>>> "Hello" ➔ "eo"
今天我们学习了所有关于 for 循环及其工作原理的知识。循环允许我们多次运行相同的代码行。
星期三:While 循环
我们今天将讨论另一种循环,即 while 循环。昨天我们看到了循环是如何工作的,以及为什么我们要使用 for 循环。当您需要基于条件而不是计数进行循环时,通常会使用 while 循环。今天我们将讨论基于条件的循环。
为了跟上这一课,让我们从之前的笔记本文件“ Week_04 ”继续,并简单地在底部添加一个 markdown 单元格,表示“ While 循环”
编写 While 循环
像 for 循环一样,while 循环以关键字**“while**”开始。接下来,我们有一个条件,就像我们用来写一个 if 语句。让我们看一个例子:
# writing your first while loop
health = 10
while health > 0:
print(health)
health -= 1 # forgetting this line will result in infinite loop
去查查那个手机。这将继续打印出健康的值,直到满足条件。在这种情况下,一旦健康不再大于零,循环就停止运行。在最后一行,我们将的生命值减 1,因此每次迭代都会将的生命值减少到接近零。如果我们没有在任何时间点减少健康,这将成为一个无限循环(这是不好的)。
While 与 For
我已经解释了几次为什么我们要使用每个循环;然而,重申概念总是好的。For 循环通常在需要对元素集合进行计数或迭代时使用。While 循环通常用于基于条件的循环。当使用 while 循环时,通常会使用布尔变量。每个循环都有它们的用例;在大多数情况下,这是个人偏好,但一般的经验法则是用 for 循环计数,用 while 循环计数。
注意
对于 while 循环,pass、break 和 continue 语句的工作方式都是一样的。
无限循环
在之前的一个单元格中,我提到过无限循环是不好的。无限循环将继续运行,直到程序中断、计算机关闭或时间停止。了解了这一点,就不要制造无限循环了。下面是一个无限循环的例子:
>>> game_over = False
>>> while not game_over:
>>> print(game_over)
如果您要在一个单元中运行它,最终您将不得不关闭 Jupyter Notebook 并重启它(或者至少是内核)。这是因为 game_over 变量永远不会变为 True ,并且该条件一直运行到 game_over 变为 True 为止。始终确保你有办法退出循环,不管是通过中断还是通过一个条件。
嵌套循环
循环中循环的概念就是我们所说的嵌套循环。循环的概念仍然适用。当使用嵌套循环时,内部循环必须总是在外部循环继续之前完成运行。让我们看一个例子:
# using two or more loops together is called a nested loop
for i in range(2): # outside loop
for j in range(3): # inside loop
print( i, j )
去查查那个手机。起初,这似乎有点令人困惑,因为这里发生了很多事情。让我们用表 4-4 分解输出。
表 4-4
跟踪嵌套循环值
|循环
|
I 的值
|
j 的值
|
内部循环计数
|
外部循环计数
| | --- | --- | --- | --- | --- | | one | Zero | Zero | one | one | | Two | Zero | one | Two | one | | three | Zero | Two | three | one | | four | one | Zero | four | Two | | five | one | one | five | Two | | six | one | Two | six | Two |
总的来说,我们可以看到内部循环运行了六次,外部循环运行了两次。只有当外循环运行时, i 的值才会增加,直到内循环结束时才会增加。内循环每次都必须从 0 数到 3,才能在外循环上运行下一次迭代。
周三练习
-
用户输入:编写一个 while 循环,继续要求用户输入,一直运行到用户输入“quit”为止。
-
双循环:在 while 循环中写一个 for 循环,从 0 数到 5,但是当它达到 3 时,它将 game_over 变量设置为 True 并且将从循环中断开。while 循环应该继续循环,直到 game_over 为 True 为止。输出应该只有 0,1,2 。
今天是一个有点短的一天,因为循环的概念是相同的,无论是一会儿还是一会儿。记住 while 循环用于条件循环,而我们使用 for 循环用于计数/迭代。
星期四:使用列表
既然我们已经学习了什么是列表以及如何使用循环,我们今天就来复习一下如何使用列表。列表对于 Python 中的任何程序来说都是一把重要的钥匙,所以我们在使用它们时需要了解我们的能力。
为了跟上这一课,让我们从之前的笔记本文件“ Week_04 ”继续,并在底部简单地添加一个 markdown 单元格,表示“使用列表”
检查长度
通常,我们需要知道一个列表中有多少项。为此,我们使用了 len() 函数:
# checking the number of items within a list
nums = [5, 10, 15]
length = len(nums) # len() returns an integer
print(length)
去查查那个手机。这将输出 3 。我们将 length 函数用于多种用途,无论是检查空列表还是在 range 函数中使用它来循环列表。
切片列表
几周前,我们讨论了切割字符串。列表以同样的方式工作,以便您能够访问特定的项目。切片遵循与范围功能开始、停止、步进相同的参数:
# accessing specific items of a list with slices
print( nums[ 1 : 3 ] ) # will output items in index 1 and 2
print( nums[ : 2 ] ) # will output items in index 0 and 1
print( nums[ : : 2 ] ) # will print every other index - 0, 2, 4, etc.
print( nums[ -2 : ] ) # will output the last two items in list
去查查那个手机。输出显示在每个语句旁边的注释中。我们使用括号符号,就好像我们在访问一个索引;然而,我们通过冒号分隔其他值。顺序永远是**【开始:停止:步进】**。默认情况下,start 为零,step 为一。如果您想保留默认值,可以选择不使用这些值。对步长位置使用负数将导致向后切片。如果在开始或停止位置使用负数,切片将从后面开始或停止。也就是说,如果您将-5 作为停止位置,它将从列表的开头一直切片到列表结束之前的五个元素。
添加项目
当需要向列表中添加项目时,Python 有两种不同的方法。
。追加( )
Append 总是将括号中的值添加到列表的后面。让我们看看:
# adding an item to the back of a list using append
nums = [10, 20]
nums.append(5)
print(nums) # outputs [10, 20, 5]
去查查那个手机。我们声明了一个包含两个条目的列表,然后将整数值 5 添加到列表的后面。
。插入( )
向列表添加条目的第二种方法是使用 insert。此方法需要一个索引来将值插入到特定位置。让我们看一个例子:
# adding a value to the beginning of the list
words = [ "ball", "base" ]
nums.insert(0, "glove") # first number is the index, second is the value
去查查那个手机。输出将导致 ['手套','球',' basex'] 。Glove 现在位于零索引中,因为我们在 insert 方法中指定了该索引。
移除项目
从列表中删除项目有几种方法,下面是主要的两种方法。
。流行( )
默认情况下, pop 方法删除列表中的最后一项;但是,您也可以指定要删除的索引。这种方法也广泛用于保存被删除的项目。当使用 pop 时,它不仅移除项目,还会返回项目。这允许我们将该值保存到一个变量中,供以后使用:
# using pop to remove items and saving to a variable to use later
items = [5, "ball", True]
items.pop( ) # by default removes the last item
removed_item = items.pop(0) # removes 5 and saves it into the variable
print(removed_item, "\n", items)
去查查那个手机。使用 pop ,我们可以看到它先移除了 True 项,然后是索引零中的元素,恰好是整数 5 。在将它从列表中弹出时,我们将它保存到一个变量中,稍后我们将它与新列表一起输出。
。移除( )
remove 方法允许我们根据给定的值从列表中删除项目:
# using the remove method with a try and except
sports = [ "baseball", "soccer", "football", "hockey" ]
try:
sports.remove("soccer")
except:
print("That item does not exist in the list")
print(sports)
去查查那个手机。这里我们将看到输出是我们的体育列表,没有足球,因为我们能够正确地删除它。现在我们之所以使用一个 try,并把去掉,是因为如果**“足球”**不在列表中,那么程序就会崩溃。
使用数字列表数据
Python 为我们提供了一些函数来处理数字数据列表,比如 min、max 和 sum。还有几个我们可以使用的,尽管这些是最常用的:
# using min, max, and sum
nums = [5, 3, 9]
print( min(nums) ) # will find the lowest number in the list
print( max(nums) ) # will find the highest number in the list
print( sum(nums) ) # will add all numbers in the list and return the sum
去查查那个手机。输出将导致 3、9 和 17 。正如他们的名字所说,他们会找到最小和最大的数字。 sum 函数将简单地把所有的数字相加。
对列表进行排序
通常,你需要使用一个排序列表。有几种方法可以做到这一点,但它们非常不同。一个将改变原始列表,而另一个返回一个副本。
已排序( )
排序的函数可以在数字或字母列表上工作,但不能在混合列表上工作。Sorted 也返回列表的一个副本,所以它不会改变原来的列表。通常如果你需要保持原件完好无损,一定要使用这个功能:
# using sorted on lists for numerical and alphabetical data
nums = [5, 8, 0, 2]
sorted_nums = sorted(nums) # save to a new variable to use later
print(nums, sorted_nums) # the original list is in tact
去查查那个手机。您会注意到我们的 nums 列表的输出仍然是我们声明它时的原始顺序。要使用新的排序列表,我们只需将它保存到一个新变量中。
。排序( )
sort 方法的用途与我们前面的 sort 函数的用途相同;但是,它会直接改变原来的列表:
# sorting a list with .sort() in-place
nums = [5, 0, 8, 3]
nums.sort( ) # alters the original variable directly
print(nums)
去查查那个手机。结果输出将是一个正确排序的列表。请记住,变量 nums 现在已经被更改为**。sort()** 直接改变数值。
条件和列表
使用列表时,通常需要检查值是否存在。现在我们将介绍如何在列表上运行条件语句。在列表上运行条件有许多原因;这只是几个例子。
使用“在”和“不在”关键字
当我们上周讨论条件语句时,我们已经看到了这些关键字的用法。使用列表时,它们有助于快速查找列表中的值:
# using conditional statements on a list
names = [ "Jack", "Robert", "Mary" ]
if "Mary" in names:
print("found") # will run since Mary is in the list
if "Jimmy" not in names:
print("not found") # will run since Jimmy is not in the list
去查查那个手机。输出结果为**“发现”、“未发现”**。在第一条语句中,我们试图查看列表中是否存在*【玛丽】,它确实存在。第二个条件语句检查是否“Jimmy”*不存在,这也是真的,所以它也运行。
检查空列表
有太多的理由需要检查空列表。这通常是为了确保您不会在程序中导致任何错误,所以让我们看看如何检查:
# using conditionals to see if a list is empty
nums = [ ]
if not nums: # could also say 'if nums == []'
print("empty")
去查查那个手机。这将输出**“空”**。评论中提到了,但是我们也可以检查它是否等于空括号。在这里,我想告诉你如何使用*【非】*关键字。要检查包含项目的列表,您需要编写以下代码:
>>> if nums:
循环和列表
您可以使用 for 和 while 循环来遍历列表中的项。
使用 For 循环
当用 for 循环遍历一个列表时,语法看起来像我们以前使用 range 函数时一样;然而,这一次我们使用了一个临时变量、in 关键字和列表名称。对于每次迭代,临时变量被赋予该项的值。让我们试一试:
# using a for loop to print all items in a list
sports = [ "Baseball", "Hockey", "Football", "Basketball" ]
for sport in sports:
print(sport)
去查查那个手机。这里我们可以看到这个单元格将输出列表中的每一项。在第一次迭代中,临时变量*“sport”被赋值为“棒球*,一旦打印出来,它就移动到下一项。
使用 While 循环
While 循环总是用于条件循环。列表 while 循环的一个很好的用例是删除一个项目。有很多用途,这只是其中之一:
# using the while loop to remove a certain value
names = [ "Bob", "Jack", "Rob", "Bob", "Robert" ]
while "Bob" in names:
names.remove("Bob") # removes all instances of 'Bob'
print(names)
去查查那个手机。输出将是我们的姓名列表,列表中没有*“Bob”。我们使用 while 循环和一个条件的组合来检查列表中的“鲍勃”*值,然后继续删除它,直到我们的条件不再为真。
周四练习
-
删除重复项:从下面的列表中删除所有重复项。提示:使用*。*计数()方法。输出应该是 ['鲍勃','肯尼','阿曼达']
>>> names = ['Bob', 'Kenny', 'Amanda', 'Bob', 'Kenny'] -
用户输入:使用 while 循环不断要求用户输入一个单词,直到他们键入“退出”。一旦他们输入一个单词,就把它添加到列表中。一旦他们退出循环,使用 for 循环输出列表中的所有项目。
今天很重要,这样我们就能理解如何使用列表,不管是条件语句还是循环。列表可以使用很多方法;在本书的其余部分,我们将更多地讨论它们。
星期五:创造刽子手
随着时间的推移,项目通常会变得更长。今天我们将利用过去四周学到的所有概念来建造 Hangman。像往常一样,随着我们编码的进行,新的概念将被引入。今天的目标是有一个功能齐全的刽子手游戏,我们可以猜测,失去一条生命,赢得或失去游戏。我们不会添加图形,虽然在我们一起完成这个项目后,你可以自己随意添加。
为了跟上这一课,让我们从之前的笔记本文件“ Week_04 ”继续,并在底部添加一个减价单元格,内容为“星期五项目:创建刽子手”
完工图纸
像往常一样,我们希望在开始编码之前就设计好最终的设计。本周不会像上周一样以图形为基础,所以我们将把重点放在运行程序的逻辑和必要步骤上。幸运的是,逻辑本质上就是玩这个游戏所需的步骤:
-
选择一个单词来玩。
-
要求用户输入。
-
检查猜测是否正确。
-
如果是,请在适当的位置显示该字母。
-
如果不是,赔一条命。
-
-
继续步骤 2 和 3,直到出现以下情况之一:
-
用户猜对了单词。
-
用户失去了他们所有的生命。
-
这是主要的游戏功能。在实际运行游戏之前,我们还需要执行其他几个步骤,比如声明游戏变量;然而,这是我们在开始编码之前需要布局的主要功能。了解这种结构将使我们能够继续我们的计划。
先前引入的线符号
就像我们在第一周如何添加行号一样,我们将为这个项目和所有其他项目引入线符号的概念。由于需要编辑以前编写的线,甚至在项目中间添加代码,我们将引入线符号的概念。这些符号将通过使用三个空方块来显示,并将代表先前编写的代码。你可以在这里看到一个例子:
1| if num > 1: ◻◻◻
3| # new code will go here
5| print( ◻◻◻
当我们在之前编写的代码之间添加行时,我将使用这三个方块来表示哪一行应该在我们正在编写的代码的上面和下面。这也意味着你应该保持这条线不变。当我们需要覆盖之前的一行时,我会让你知道。当你看到这三个方块时,一定要注意行号,因为这将有助于让你知道你是否错过了一行。
注意
点按单元格的边后按下“L”来打开线条
添加导入
我们将在一个单元格中编写这个程序,它大约有 50 行长。第一步是导入一些我们需要的附加函数:
1| # import additional functions
2| from random import choice
3| from IPython.display import clear_output
第二行是导入一个名为**“choice”**的函数,它将从列表中选择一个随机项目。我们将用它来随机选择单词。第三行是导入一个 Jupyter Notebook 特定的函数,该函数清除输出。当使用循环时,如果我们不清除输出,它将继续在彼此之上输出。
声明游戏变量
下一步是理解运行游戏需要哪些变量,并声明它们。如果你想到 Hangman 和我们需要跟踪的东西,我们需要跟踪用户的生活,他们试图猜测的单词,可供选择的单词列表,以及游戏是否结束:
5| # declare game variables
6| words = [ "tree", "basket", "chair", "paper", "python" ]
7| word = choice(words) # randomly chooses a word from words list
8| guessed, lives, game_over = [ ], 7, False # multi variable assignment
第七行声明了一个名为单词的变量,它将从我们的单词列表中选择一个随机项目。第八行是我们一起声明三个变量的地方;猜测的将被赋予一个空列表,生命将被设置为 7 , game_over 将被声明为假。
注意
在我们编码的过程中,可以随意编写打印语句来检查每个变量的值。这有助于了解我们所声明的内容。
生成隐藏单词
在游戏中,我们希望用户能够看到单词中有多少个字母。为此,我们可以创建一个字符串列表,其中每个字符串都是一个下划线。列表中的项目数将被设置为与所选单词的长度相同:
10| # create a list of underscores to the length of the word
11| guesses = [ "_ " ] * len(word)
在第 11 行,我们声明了一个名为guess的变量,它被设置为一个下划线列表。我们通过将列表乘以单词的长度得到合适的长度。
创建游戏循环
无论程序大小,每个游戏都有一个主循环。我们的主循环将执行我们在最终设计部分定义的逻辑。与其一次写完,不如让我们一步一步来。第一步是能够接受用户输入并停止玩游戏:
13| # create main game loop
14| while not game_over:
15| ans = input("Type quit or guess a letter: ").lower( )
17| if ans == "quit":
18| print("Thanks for playing.")
19| game_over = True
去查查手机。如果您输入*“退出*”,程序应该会停止,因为我们正在循环,直到 game_over 被设置为 True ,这仅在我们输入*“退出*”时发生。
注意
在继续之前,务必确保单元运行完毕。
输出游戏信息
下一步是开始向用户输出信息。让我们用一个格式良好的语句输出他们的生活和他们试图猜测的单词:
14| while not game_over: ◻◻◻
15| # output game information
16| hidden_word = "".join(guesses)
17| print( "Word to guess: { }".format(hidden_word) )
18| print( "Lives: { }".format(lives) )
20| ans = input( ◻◻◻
去查查手机。根据选择的单词,您将得到不同的输出。如果选择的单词是四个字母,我们将得到“单词猜:_ _ _ _ _ _ _”和“生命:7 ”)的输出。格式没什么新意,但是第 16 行呢?我们之所以能够在第 17 行创建一个下划线字符串输出,是因为 join 方法。它声明我们希望将猜测列表中的所有项目连接在一起,中间没有空格。例如:
>>> chars = ['h', 'e', 'l', 'l', 'o']
>>> print('-'.join(chars))
前面两行将输出“ h-e-l-l-o ”。这是一个将列表显示为字符串的简单方法。
核实猜测
下一步是检查用户的输入是否是正确的猜测。我们暂时不会更改任何字母,因为我们首先要确保我们可以识别正确的猜测,并输出他们正确的猜测或删除一个生命:
24| game_over = True ◻◻◻
25| elif ans in word: # check if letter in word
26| print("You guessed correctly!")
27| else: # otherwise lose life
28| lives -= 1
29| print("Incorrect, you lost a life.")
去查查手机。如果你继续错误地猜测,你会注意到生命会降到零度以下。一定要猜出一个正确的字母和一个不正确的字母,这样才知道这是有效的。
清除输出
现在我们的程序进行得更深入了,我们可以看到这个循环不断地输出低于先前输出的信息。让我们开始清除输出:
20| ans = input( ◻◻◻
22| clear_output( ) # clear all previous output
24| if ans == 'quit': ◻◻◻
去查查手机。你会注意到,无论我们玩多长时间,它都会正确地清除之前显示的信息。这是 Jupyter 笔记本特有的功能。
创造失败的条件
下一个逻辑操作将是创造一种失败的方式,因为我们的生活可以降到零度以下:
31| print('Incorrect, ◻◻◻
33| if lives <= 0:
34| print("You lost all your lives, you lost!")
35| game_over = True
去查查手机。现在如果你输了所有的生命,游戏会停止运行,告诉你输了。请记住,循环只运行到 game_over 为真,这是一旦生命的变量下降到零时我们设置的值。
处理正确的猜测
既然我们可能会输,我们需要看到正确猜测的能力。为了理解如何改变显示的字母,我们首先需要记住输出的是什么。我们的猜测列表被转换成一个字符串并输出。这意味着当用户猜对了,我们需要改变我们的猜测列表中的条目到它们相应的位置。列表的长度与我们在单元格开头选择的单词的长度相同,因此每个下划线代表一个字母位置。如果单词是**“运动”**,那么“ _ _ _ _ ”中的第一个下划线将代表“ s ”。我们只需要用猜测的字母替换列表中正确的下划线。我们可以通过使用 for 循环并跟踪索引来做到这一点:
28| print('You guessed correctly!') ◻◻◻
30| # create a loop to change underscore to proper letter
31| for i in range( len(word) ):
32| if word[ i ] == ans: # comapares values at indexes
33| guesses[ i ] = ans
34| else: ◻◻◻
去查查那个手机。现在当猜中一个正确的字母时,它会输出变化。for 循环循环到单词的长度,我们使用变量" i "来跟踪索引。然后我们检查每个字符是否等于猜测的字母。如果是,那么我们将该项从下划线改为在该索引处猜测的字母。查看表 4-5 中的流程示例。让我们用**【流行】**来表示单词,用 p 来表示猜测。
表 4-5
取索引值检查猜测
|ans 的值
|
I 的值
|
单词[i]的值
|
条件值
|
变化后的猜测值
| | --- | --- | --- | --- | --- | | p ' | Zero | p ' | 真实的 | ['p ',' _ ',' _ '] | | p ' | one | 的 | 错误的 | ['p ',' _ ',' _ '] | | p ' | Two | p ' | 真实的 | ['p ',' _ ',' p'] |
创造成功的条件
完成这个项目的最后一步是建立成功的条件。为了获胜,用户需要猜出随机选择的单词中的所有字母。我们已经跟踪了他们正确猜测的单词,所以我们只需要对照随机单词进行检查:
40| game_over = True ◻◻◻
41| elif word == "".join(guesses):
42| print("Congratulations, you guessed it correctly!")
43| game_over = True
去查查手机。现在,如果用户猜对了所有字母,就可以正式获胜。我们使用与前面相同的连接方法,将我们的列表转换成一个字符串,这样,如果列表中还有下划线,连接的字符串就不等于随机单词。然后,我们打印一份祝贺,并将我们的 game_over 变量改为 True,以结束循环。
输出猜测的字母
虽然我们的游戏现在已经完成,我们可以赢或输,我们应该添加一个关键的功能,这是处理以前猜测的字母。每当用户猜出了之前的字母,他们不应该因此受到惩罚,但是他们也应该能够看到之前的猜测。在这个项目开始的时候,我们创建了一个名为 guessed 的变量,到现在都没有用过。到目前为止,这个变量仍然是一个空列表,所以让我们来实现它。在我们添加到列表中之前,让我们确保可以正确地打印出信息:
16| hidden_word = ◻◻◻
17| print("Your guessed letters: { }".format(guessed) )
18| print("Word to guess ◻◻◻
去查查手机。在我们输出信息的顶部,我们现在打印出猜测字母的完整列表。以列表的形式保留它是完全没问题的。即使您猜测,它仍然会显示一个空列表,因为我们还没有添加该功能。
添加猜测的字母
现在让我们添加将用户的猜测添加到我们的猜测列表的功能:
37| print("Incorrect, ◻◻◻
39| if ans not in guessed:
40|| guessed.append(ans) # add ans to guessed list
42| if lives <= 0: ◻◻◻
去查查手机。现在猜测列表会随着用户玩游戏而更新。
处理先前的猜测
最后一项任务是确保当他们再次猜中同一封信时,他们不会被夺走一条生命,而是提醒他们已经被猜中了。我们需要重写整个条件语句来检查字母是否在单词 though 中:
27|| game_over = True ◻◻◻
28| elif ans in word and ans not in guessed:
29|| print("You guessed correctly!") ◻◻◻
34| guesses[ i ] = ans ◻◻◻
35| elif ans in guessed:
36|| print("You already guessed that. Try again.")
37| else: ◻◻◻
去查查手机。我们不得不更改第 28 行的 elif 语句,因为我们还需要检查该字母是否尚未添加到猜测列表中。在第 35 行,我们添加了第二个 elif 语句,该语句将检查该字母是否在猜测的列表中。请记住,一旦 if/elif 语句运行,下面的语句将不会运行。如果那两个条件句都不是真,那么说明他们还没猜到字母,而且不在随机词里。游戏现在已经完成了全部功能。
最终输出
祝贺您完成这个项目!由于项目的规模,完整的代码将不会写在这里。相反,你可以在 Github 上找到本书资源文件所在的完整版本的代码。你可以在书的前面找到链接。每周的所有资源文件都位于该链接中。要找到这个项目的具体代码,只需打开或下载“ Week_04.ipynb ”文件。如果您在这个过程中遇到了错误,请确保将您的代码与该文件中的代码进行交叉引用,看看您可能在哪里出错了。所有未来项目的最终代码输出也可以在同一个位置找到,所以一定要将这个页面加入书签。
多好的一天啊!我们能够使用循环的概念,以及列表的力量来创建一个有趣的游戏。试着添加你自己的信号弹,或者打破它,以进一步了解什么可能或可能不工作。
每周总结
这无疑是漫长的一周,充满了大量的信息。一定要花些时间练习这些概念,或者自己练习,或者完成周末练习。我们讨论了为什么列表在 Python 中如此重要,以及如何在我们的程序中使用它们。还介绍了 Python 提供的两个循环,for 循环和 while 循环。使用循环,我们可以根据需要多次重新运行代码,或者迭代列表之类的数据集合。如果你对所有的信息感到不知所措,请放心,我们做的每件事都使用循环和列表。这会给你大量的练习和重复。
挑战问题解决方案
尽管我们在寻找一个特定的答案,但这是一个有点棘手的问题。如果你的第一个动作是转身问:“出了什么问题?"或"我为什么要撤离这座城市?”,那你回答对了。之所以需要先问这个问题,是因为不同的问题需要不同的解决方案。如果你开始写一个需要使用汽车的疏散计划,如果问题是所有的街道都被淹没了呢?建议人们开车出城是不明智的。有时候问题的答案就是问题本身。另一个教训是,你应该总是后退一步,思考每个问题。永远不要假设你马上就知道解决方案;问问题没问题。
每周挑战
要测试你的技能,请尝试以下挑战:
-
金字塔:使用 for 循环建立 x 的金字塔。它应该是模块化的,这样,如果您循环到 5 或 50,它仍然创建均匀间隔的行。提示 : *将字符串“x”乘以行。*例如,如果您循环到范围 4,它应该产生以下结果:
>>> x >>> x x >>> x x x -
Output Names :编写一个循环,遍历一个项目列表,只输出字符串中有字母的项目。以下面的列表为例,应该只输出**【约翰】和【阿曼达】**:
>>> names = ['John', ' ', 'Amanda', 5] -
Convert Celsius :给定一个以摄氏度为单位的温度列表,编写一个循环来遍历该列表,并输出转换为华氏温度的温度。提示:换算为“F =(9/5)÷C+32”:
>>> temps = [32, 12, 44, 29] Output would be [89.6, 53.6, 111.2, 84.2] ```**
五、函数
本周开始函数的话题。除了循环,函数可能是最难理解的主题之一。出于这个原因,这一整周都致力于只涵盖函数。这也是编程中比较重要的课题之一。知道如何使用函数将极大地提高你的编程技能。
函数给了我们能力,使我们的程序更加强大和干净,同时也节省了我们的时间。我们将在第一天回顾它们是如何工作的,但是我们使用函数的原因是因为它具有编写一次并重复调用的能力。
我们已经构建的许多程序都可以从函数的使用中受益,尤其是像 Hangman 这样的游戏。在周末,我们将构建一个类似购物车列表的程序。我们将了解为什么将添加、删除和显示等任务分离到不同的函数中很重要。
概述
-
如何使用函数以及它们是什么
-
使用参数传递数据
-
从函数返回数据
-
理解范围及其重要性
-
创建购物车程序
挑战问题
请记住,算法只不过是一组循序渐进的指令。如果我们要写一个换灯泡的算法,会是什么样子?有哪些需要考虑的问题?需要几个步骤?最有效的方法是什么?使用下面的算法,可能会出现什么问题?
-
取出备用灯泡。
-
关闭给当前灯泡供电的开关。
-
拧下电流灯泡。
-
拧入备用灯泡。
-
打开给新灯泡供电的开关。
-
如果备用灯泡没有打开,重复步骤 1 至 5。
星期一:创建和调用函数
今天的课程是关于理解什么是函数,函数的阶段,以及如何编写函数。我们将发现为什么它们在程序中如此重要,以及它们将如何使我们的生活变得更容易。
为了继续今天的内容,让我们从“ python_bootcamp ”文件夹中打开 Jupyter 笔记本。一旦它打开,创建一个新文件,并将其重命名为“周 _05。"接下来,制作第一个标题为:"的单元格 markdown,创建&调用函数。“我们将开始在那个牢房下面工作。
什么是函数?
编程最好的参考资料之一是 w3schools。 1 他们甚至还有 Python 教程。他们的官方文档对函数的描述如下:
函数是一段代码,只有在被调用时才会运行。
您可以将数据(称为参数)传递到函数中。
函数可以返回数据结果。 2
程序经常需要重复运行相同的代码,尽管循环在这方面有所帮助,但我们不希望在整个程序中多次编写相同的循环。这个问题的解决方案是使用一个函数。它们本质上存储了只在被调用时才运行的代码。
所有函数通常都与单一任务或程序相关联。这使得我们更容易将程序分解成函数。如果您构建一个需要重复打印五行信息的程序,并且您需要在五个不同的地方输出它,您将需要编写 25 行代码。使用函数时,您可以将这五行存储在一个块中,并在需要时调用该函数,结果是五行输出信息,五行调用函数,总共十行。这导致了一个更有效的程序。
函数语法
像循环一样,函数遵循一个精确的模式来创建每一个函数。它们都是以关键字“ def ”开头,后面是函数的名。该名称是任意的,可以是除 Python 关键字和先前定义的函数之外的任何名称。名字后面紧跟着的是括号,括号内是参数。我们明天才讨论参数,所以要知道参数是可选的,但是括号是必需的。最后,像任何其他 Python 语句一样,我们需要一个结尾冒号。示例见图 5-1 。
图 5-1
函数语法
编写您的第一个函数
现在我们知道了语法结构的样子,让我们继续写我们自己的:
# writing your first function
def printInfo( ): # defines what the function does when called
print("Name: John Smith")
print("Age: 45")
printInfo( ) # calls the function to run
printInfo( ) # calls the function again
去查查手机。我们定义了一个名为 printInfo 的函数,它在每次被调用时打印两行信息。下面我们调用函数两次,输出信息两次。这似乎不是一个更有效的程序,但是想象一下你需要在一个程序中输出 20 次同样的信息。简洁高效。
函数阶段
在 Python 中,每个函数有两个阶段。第一阶段是函数定义。您可以在这里定义函数的名称、它应该接受的任何参数,以及它应该在与之相关的代码块中做什么。见图 5-2 。
图 5-2
函数生命周期的两个步骤(定义和调用)
第二阶段被称为函数调用。函数在被调用之前是不会运行的,所以你可以定义尽可能多的函数,但是如果你从来不调用其中的一个,那么什么都不会发生。当您调用一个函数时,它将运行定义中的代码块。
UDF 与内置
在不知不觉中,你一直在使用函数。范围、打印、镜头等函数。,都被称为“内置函数。它们被包含在 Python 中,因为它们有特定的用途来帮助构建我们的应用程序。既然我们正在学习函数,我们可以开始创建我们自己的所谓的UDF或用户定义函数
执行计算
让我们再看一个基本函数的例子,但是这次不仅仅是打印代码块内部:
# performing a calculation in a function
def calc( ):
x, y = 5, 10
print(x + y)
calc( ) # will run the block of code within calc and output 15
去查查手机。每次调用 calc 函数时,我们都会得到一个输出值 15 。
周一练习
-
打印名字:定义一个名为 myName 的函数,让它在被调用时打印出你的名字。
-
Pizza Toppings :定义一个函数,打印出所有你喜欢的 Pizza Toppings。调用该函数三次。
虽然今天没有太多的编码,但是理解函数的价值是很重要的。现在我们可以将代码分成块,这将使程序更容易阅读和运行。
星期二:参数
我们使用函数的主要原因之一是为了使我们的代码模块化。今天的主题是了解如何在函数中使用参数以及它们是什么。
为了继续本课,让我们从之前的笔记本文件“ Week_05 ”继续,并在底部添加一个标有“参数”的降价单元格。
什么是参数?
参数是在函数定义中声明的临时变量。虽然我们到目前为止编写的函数执行特定的任务,但是它们不是模块化的,因为它们总是为每个调用输出相同的响应。当要调用不同值的函数时,需要使用参数。在函数定义的括号内是您要声明参数名称的地方。这是一个任意变量名,用于引用函数块中的值;但是,您通常希望它与您正在处理的数据相关。当调用函数时,您将传入运行代码块所需的值。取图 5-3 。
图 5-3
接受函数的参数
注意
参数是传递给函数调用的值。在上图中,第 3 行将参数“John”传递给 printName 函数,该值将被传递给参数名
该函数由括号内的参数“ name 定义。同样,它可以被称为任何东西,但是我们期望传入一个人的名字。该代码块在执行时将使用格式化打印语句中该参数的值。第 3 行的调用是我们将值传递给函数的地方,称为参数。在这个例子中,我们将得到“你好约翰”的输出。我们现在可以调用这个函数,传入任何我们想要的字符串值,它会打印出来。这个函数现在是模块化的。
传递单个参数
让我们使用图 5-3 中的例子来创建我们的第一个接受参数的函数:
# passing a single parameter into a function
def printName(full_name):
print( "Your name is: { }".format(full_name) )
printName("John Smith")
printName("Amanda")
去查查手机。我们会得到两个不同的输出,它们使用相同的函数。参数允许我们为每个调用传递不同的信息。
多参数
前面的示例将字符串数据类型传递给函数,因此让我们看看如何传递数字并创建一个格式良好的打印语句:
# passing multiple parameters into a function
def addNums(num1, num2):
result = num1 + num2
print( "{ } + { } = { }".format(num1, num2, result) )
addNums(5, 8) # will output 13
addNums(3.5, 5.5) # will output 9.0
去查查那个手机。我们的函数定义期望两个数字被传入参数 num1 和 num2 。在函数块中,我们通过参数名来引用这些值。
传递列表
当大量数据存储在列表中时,传递它们通常是最容易的。因此,函数非常擅长在列表上执行重复的任务。让我们看一个例子:
# using a function to square all information
numbers1 = [ 2, 4, 5, 10 ]
numbers2 = [ 1, 3, 6 ]
def squares(nums):
for num in nums:
print(num**2)
squares(numbers1)
squares(numbers2)
去查查手机。你可以看到它会输出所有的平方数。这比为每个列表编写两次 for 循环要高效得多。这就是函数和传入参数的美妙之处。
注意
记住 nums 是一个任意的名字,是我们在函数块中引用的变量。
默认参数
在许多情况下,参数可以与默认值相关联。以 pi 的值为例;它将始终是 3.14,因此我们可以将一个名为 pi 的参数设置为该精确值。这允许我们调用已经为 pi 定义了值的函数。如果你想让 pi 有一个更简洁的值,你可以,但是一般来说 3.14 就足够了:
# setting default parameter values
def calcArea(r, pi=3.14):
area = pi * (r**2)
print( "Area: { }".format(area) )
calcArea(2) # assuming radius is the value of 2
去查查手机。现在我们可以运行这个函数,而不需要为 pi 传递一个值。默认参数必须始终跟随非默认参数。在这个例子中,半径必须首先声明,然后是 pi 。
使参数可选
有时,您需要创建带有可选参数的函数。最好的例子总是中间名;有些人有,有些人没有。如果我们想写一个在两种情况下都能正确输出的函数,我们需要把中间的名字作为可选参数。我们通过将空字符串值指定为默认值来实现这一点:
# setting default parameter values
def printName(first, last, middle=""):
if middle:
print( "{ } { } { }".format(first, middle, last) )
else:
print( "{ } { }".format(first, last) )
printName("John", "Smith")
printName("John", "Smith", "Paul") # will output with middle name
去查查手机。无论您是否传入中间名,该函数都将高效运行。请记住我们参数的顺序!根据函数定义,参数必须从左到右排列。如果在第二次调用中*【保罗】被作为第二个值放在【约翰】之后,那么我们的函数会将【保罗】赋给参数【最后一个*】
命名参数赋值
在函数调用期间,您可以显式地将值赋给参数名。当您不想混淆传入值的顺序时,这很有用,因为默认情况下它们是从左到右工作的。如果您愿意,可以使用参数名为每个参数赋值,但大多数情况下这是不必要的。让我们来看一个例子:
# explicity assigning values to parameters by referencing the name
def addNums(num1, num2):
print(num2)
print(num1)
addNums(5, num2 = 2.5)
去查查手机。这里,我们使用一个关键字参数在调用中显式地分配了 num2 的值。
*参数
使用* args 允许您向函数传递可变数量的参数。这允许您使函数更加模块化。神奇的不是这里的关键字“args;实际上是一元运算符()允许我们执行这个特性。理论上,你可以用任何人替换 args 这个词,比如“ 数据,它仍然可以工作。然而,args 是整个行业的默认和通用标准。让我们看看如何在函数调用中使用参数:
# using args parameter to take in a tuple of arbitrary values
def outputData(name, *args):
print( type(args) )
for arg in args:
print(arg)
outputData("John Smith", 5, True, "Jess")
去查查手机。您会注意到 args 参数将调用中未赋值的所有值作为一个元组,作为第一个 print 语句的输出。然后,我们输出元组中的每个参数。当访问块中的 args 参数时,不需要包含一元运算符。注意"约翰·史密斯"没有被打印出来。那是因为我们在函数定义中有两个参数, name 和* args 。函数调用中的第一个参数被映射到 name 参数,其余的被插入到 args 元组中。当您不确定会有多少个参数时,这是一个有用的机制。
**夸格斯
像 args 一样, kwargs 允许我们在函数中接受任意数量的值;然而,它作为一个带有关键字参数的字典。关键字参数是通过键传递的值,这使得我们可以在函数块中轻松地访问它们。同样,这里的神奇之处在于两个一元操作符(**)而不是 kwargs 的关键字。让我们来看看:
# using kwargs parameter to take in a dictionary of arbitrary values
def outputData(**kwargs):
print( type(kwargs) )
print( kwargs[ "name" ] )
print( kwargs[ "num" ] )
outputData(name = "John Smith", num = 5, b = True)
去查查手机。这一次,我们可以看到该类型是一个字典,我们能够像处理任何其他字典一样输出 kwargs 参数中的每个键值对。这个单元格中的关键字参数在函数调用中,在这里我们专门声明了一个要传递给函数的键和值。
星期二练习
-
用户输入:要求用户输入一个单词,并将该单词传递给一个函数,该函数检查该单词是否以大写字母开头。如果确实输出“真,否则“假”。
-
没有名字:定义一个函数,它接受两个参数*,名字和姓氏*,并且这两个参数都是可选的。如果没有值传入参数,它应该输出“没有名字传入”;否则,它应该打印出名称。
今天讲的都是函数参数以及如何使用它们。参数的使用使我们的函数在程序中模块化,这样我们就可以成功地减少编写的代码行。
周三:返回声明
到目前为止,我们已经打印出了函数所改变的数据,但是如果以后需要访问这些信息,该怎么办呢?这就是使用 return 语句的地方。函数可以操作数据,然后将数据发送回函数调用发生的地方,以保存信息供以后使用。今天我们将学习如何做到这一点,以及它为什么有用。
为了跟上这一课,让我们从笔记本文件“ Week_05 ”继续,只需在底部添加一个标有“退货单”的降价单元格
它是如何工作的
图 5-4 描绘了如何先计算传入函数的两个参数,然后返回到调用的原始位置存储到变量中。这个变量现在可以在程序的后面与那个值一起使用。
图 5-4
返回信息并存储到变量中
您可以返回任何数据类型,但只能返回一个变量。当您需要返回多条数据时,您将返回一组数据:
>>> def returnMultiple():
>>> a = 5
>>> b = 10
>>> return [a, b] # one data type holding multiple items
使用返回
return 语句用于将信息发送回函数调用发生的地方。到目前为止,我们已经使用了 print 语句来输出信息,但是如果我们需要在程序的后面访问该值,这就行不通了。相反,我们可以返回值并保存到一个变量中,以便以后使用。让我们来看几个例子:
# using return keyword to return the sum of two numbers
def addNums(num1, num2):
return num1 + num2
num = addNums(5.5, 4.5) # saves returned value into num
print(num)
print( addNums(10, 10) ) # doesn't save returned value
去查查手机。我们将得到 10 和 20 作为输出。当我们第一次调用 addNums 时,它用 5.5 和 4.5 运行函数并返回总和。然后,它将返回值存储在 num 中。第二次调用该函数时,我们简单地就地打印它。从这里开始,我们可以重用存储在 num 中的值,但不能重用第二次调用返回的值。
三元运算符
三元运算符是一种简化的 Python 分支语句。这些运算符可用于将值赋给变量,或者在这种情况下,决定从函数返回什么:
# shorthand syntax using a ternary operator
def searchList(aList, el):
return True if el in aList else False
result = searchList( [ "one", 2, "three" ], 2) # result = True
print(result)
去查查手机。三元运算符返回 True,因为满足给定的条件。通常写出的相同代码如下所示:
>>> if el in aList:
>>> return True
>>> else:
>>> return False
如果可以的话,尽量少写是一个好习惯,但这不是必须的。
周三练习
-
全名:创建一个函数,接受名和姓,并返回两个名字的组合。
-
用户输入:在一个函数中,请求用户输入。让这个函数返回要存储在函数外部变量中的输入。然后打印出输入内容。
今天我们学习了如何从函数中获取信息。这将允许我们保存它处理的数据以备后用。
星期四:范围
今天我们要讨论一个叫做范围的重要概念。这个概念处理程序中声明的变量的可访问性。我们将讨论不同类型的作用域以及如何处理它们。
为了跟上这一课,让我们从之前的笔记本文件“ Week_05 ”继续,并简单地在底部添加一个标有“ Scope ”的单元格
范围的类型
在 Python 中,作用域有三种类型:全局、函数、类。我们还没有复习类,所以我们将在下一章讨论类的范围。在不知道的情况下,我们使用了另外两种类型的作用域。全局作用域是指你声明一个变量可以被整个文件或应用程序访问。到目前为止,我们声明的大多数变量都是全局变量;然而,在你编写的大多数程序中,你会想要避免全局变量。不过目前在 Jupyter 笔记本上还可以。函数作用域是指被声明的变量,只能在函数内部访问。在函数内部声明的变量不能在函数外部访问,因为一旦函数终止,在函数内部声明的变量也会终止。
全局范围访问
定义了全局属性后,文件的其余部分就可以访问它们了。但是,我们必须记住函数作用域是如何工作的。即使您声明了一个整个文件都可以访问的变量,它在函数中也是不可访问的。让我们看一个例子:
# where global variables can be accessed
number = 5
def scopeTest( ):
number += 1 # not accessible due to function level scope
scopeTest( )
去查查手机。我们最终会收到一个错误,因为该函数仅限于在其中声明或传入的变量。
注意
传入时,它只传递值,不传递变量。
处理函数范围
当处理函数中声明的变量时,通常不需要在函数外部访问它。但是,为了访问该值,最佳做法是返回它:
# accessing variables defined in a function
def scopeTest( ):
word = "function"
return word
value = scopeTest( )
print(value)
去查查手机。现在我们可以访问函数中定义的单词,我们只需将返回值赋给另一个变量就可以了。
原地算法
当传递变量到一个函数中时,你只是传递那个变量的值,而不是变量本身。使得以下内容不会改变变量 num :
>>> num = 5
>>> def changeNum(n):
>>> n += 5
>>> print(num)
但是,当通过索引改变信息时,这是不同的。由于索引的工作方式,通过内存位置而不是引用,通过索引位置改变列表中的元素将改变原始变量。让我们来看一个例子:
# changing list item values by index
sports = [ "baseball", "football", "hockey", "basketball" ]
def change(aList):
aList[ 0 ] = "soccer"
print("Before Altering: { }".format(sports) )
change(sports)
print( "After Altering: { }".format(sports) )
去查查手机。注意当函数被调用时, sports 列表中的第一项是如何变化的。这是由于在传入列表时索引本身的值发生了变化。这些被称为就地算法,因为无论你在哪里改变信息,它都会直接改变内存位置的值。
周四练习
-
Names :创建一个函数,在给定的索引处用 name 参数改变传入的列表。这样,如果我传入*【比尔】和索引 1,,它将把【富人】变成【比尔】*在下面使用列表和函数定义:
>>> names = ['Bob', 'Rich', 'Amanda'] >>> def changeValue(aList, name, index):
今天对于理解可变可达性是如何工作的很重要。知道这些信息会保证变量的安全。
星期五:创建购物车
对于今天的项目,我们将构建一个在列表中存储产品的应用程序。我们将能够添加、删除、清除和显示购物车中的产品。将使用过去几周教授的所有概念。
为了继续本课,让我们从之前的笔记本文件“ Week_05 ”继续,并在底部添加一个 markdown 单元格,内容为“星期五项目:创建购物车”
完工图纸
正如我们本周介绍的函数一样,最终的设计将基于我们程序动作的逻辑。函数执行特定的任务,通常是一个动作。对于我们的购物车程序,我们需要考虑的操作是添加、删除、清除和显示购物车中的商品。逻辑设计将如图 5-5 所示。
图 5-5
购物车程序逻辑
我们将确保有一个包含循环和处理用户输入的主函数。
初始设置
像上周的项目一样,我们将在单个单元格中创建程序,所以请确保您熟悉我们在该项目中使用的概念。首先,让我们从 Jupyter Notebook 导入清算函数*,并声明一个要使用的全局变量:*
1| # import necessary functions
2| from IPython.display import clear_output
4| # global list variable
5| cart = [ ]
我们想要声明一个全局变量 cart ,以便在整个程序中使用。我们将使用一个列表,因为我们需要存储几个条目。使用列表还允许我们直接编辑变量,而不必因为项目分配的工作方式而传递变量。
添加项目
正如初始设计中所述,我们首先要创建我们的函数。我们将从向我们的购物车变量添加商品的函数开始:
7| # create function to add items to cart
8| def addItem(item):
9| clear_output( )
10| cart.append(item)
11| print( "{ } has been added.".format(item) )
我们在创建主循环之前不会调用这个函数。当被调用时,该函数将清除输出,追加传入参数的项,并输出给用户。
移除项目
接下来,我们将创建从我们的购物车变量中移除商品的函数:
13| # create function to remove items from cart
14| def removeItem(item):
15| clear_output( )
16| try:
17| cart.remove(item)
18| print( "{ } has been removed.".format(item) )
19| except:
20| print("Sorry we could not remove that item.")
我们希望确保在 remove 语句周围包含一个 try 和 except 子句,因为当删除一个不存在的项目时,程序会崩溃。这可以防止这种情况发生,并且可以正确地删除该项目,或者向用户输出该项目不起作用。
展示购物车
我们希望用户能够随时查看购物车,这使用了一个简单的循环:
22| # create a function to show items in cart
23| def showCart( ):
24| clear_output( )
25| if cart:
26| print("Here is your cart:")
27| for item in cart:
28| print( "- { }".format(item) )
29| else:
30| print("Your cart is empty.")
在该函数中,我们首先清除输出,然后检查购物车中是否有商品。如果它是空的,我们让用户知道;否则,我们将循环遍历这些项目,每行输出一个。
清理购物车
我们需要的最后一个函数是清理购物车的能力:
32| # create function to clear items from cart
33| def clearCart( ):
34| clear_output( )
35| cart.clear( )
36| print("Your cart is empty.")
使用内置的 clear 方法,我们清除购物车中的所有商品,并让用户知道。
创建主循环
到目前为止,我们已经创建了处理用户动作的函数。现在我们需要设置程序的主函数,它将包含主循环和结束函数:
38| # create main function that loops until the user quits
39| def main( ):
40| done = False
42| while not done:
43| ans = input("quit/add/remove/show/clear: ").lower( )
45| # base case
46| if ans == "quit":
47| print("Thanks for using our program.")
48| showCart( )
49| done = True
51| main( ) # run the program
去查查手机。你现在应该可以输入**“quit”**并退出程序;否则,它将继续运行。除了退出,我们还没有设置要做什么;然而,我们已经确保我们的基本情况设置正确,以免产生无限循环。我们还使用布尔变量 done 来跟踪主循环是否完成。
处理用户输入
这个程序的最后一步是添加我们之前创建的处理用户输入的函数:
49| done = True ◽◽◽
50| elif ans == "add":
51| item = input("What would you like to add? ").title( )
52| addItem(item)
53| elif ans == "remove":
54| showCart( )
55| item = input("What item would you like to remove? ").title( )
56| removeItem(item)
57| elif ans == "show":
58| showCart( )
59| elif ans == "clear":
60| clearCart( )
61| else:
62| print("Sorry that was not an option.")
64| main( ) # run the program
去查查手机。我们已经包含了几个 elif 语句来处理用户的输入。现在,根据他们的选择,我们将能够调用必要的函数。在第 51 和 55 行,我们接受用户的第二次输入,键入他们想要添加或删除的项目,但为了区分大小写,我们确保将其更改为标题大小写。如果他们没有选择合适的任务来执行,我们确保通过 else 子句让他们知道。
最终输出
祝贺您完成这个项目!由于项目的规模,你可以在 Github 上找到完整版本的代码。要找到这个项目的具体代码,只需打开或下载“ Week_05.ipynb ”文件。如果您在这个过程中遇到了错误,请确保将您的代码与该文件中的代码进行交叉引用,看看您可能在哪里出错了。
今天,我们能够使用函数构建一个完整的购物车程序。我们可以看到,我们的主循环是干净的,易于阅读。即使是这个小程序,也能看出函数的威力。
每周总结
本周是我们提高编程技能的一大步。我们了解到函数在减少代码行数方面非常有用。它们有助于使我们的程序更高效、更易读。它们可以使用参数变得模块化,甚至可以使用 return 关键字返回特定的数据。我们讨论的最后一个概念是如何处理项目中的范围,以及它如何处理变量的可访问性。在周末,我们一起构建了购物车程序,以展示在程序中使用函数的能力。下周我们将继续学习称为数据集合的高级变量类型的知识。
挑战问题解决方案
这个挑战的目的是让你开始思考所安排的步骤中可能出现的错误。在你开始编程算法之前,你需要理解你设计的步骤可能会出错,因为计算机只有在你编程后才会变得聪明。这个算法有几个问题。最明显的是在第二步和第三步之间,我们试图更换灯泡。你检查过灯泡是否太热而不能触摸了吗?在这种情况下,我们没有,所以任何人直接遵循这个算法可能会烧伤。作为人类,基本本能占据了主导地位,我们会停止触摸它,但计算机会继续执行它们被告知的任务。其他突出的问题包括检查替换灯泡的类型是否正确,以及如何处理我们刚刚替换的灯泡。算法没有指定一个步骤来适当地处理它,那么我们就永远把它留在我们手中吗?这些是我们在更换灯泡时需要考虑的步骤。当你开始构建自己的算法时,你不仅需要确保算法有效,还需要考虑如何处理容易出错的情况。
每周挑战
要测试你的技能,请尝试以下挑战:
-
重构 Hangman :这是一个很大的任务,所以要轻装上阵,但是要尝试重构上周的 Hangman 项目来使用函数。想想 Hangman 需要什么动作,把那些任务变成函数。
-
通过索引移除:在购物车程序中,设置移除函数,这样你也可以通过索引移除。设置列表,使其以编号列表的形式打印出来,当被要求删除一个项目时,用户也可以在列表项目旁边键入一个数字。例如,使用下面的代码,你可以输入 "1" 来删除 "Grapes" :
>>> 1) Grapes >>> What would you like to remove? 1
2
www.w3schools.com/python/python_functions.asp
六、数据收集和文件
Python 中有几种数据结构。本周我们将讨论字典、集合、元组和冷冻集合,以增加我们的集合知识。每一种都有特定的用途,我们将看到它们之间的区别。
知道如何处理任何语言的文件都很重要。为了处理数据,我们需要知道如何读写几种类型的文件。我们将介绍如何处理文本文件和 ?? 文件。
概述
-
理解词典
-
使用字典
-
学习其他重要的数据收集
-
使用文件
-
使用文件创建示例数据库
挑战问题
本周的挑战是写一个函数来检查一个单词是否是回文。该函数应该接受一个参数并返回 True 或 False。先试着把函数写在纸上,再试着编程!
星期一:字典
今天,我们将学习字典中有价值的数据集合。它们使用键存储信息,比 Python 列表高效得多。
为了继续今天的内容,让我们从“ python_bootcamp ”文件夹中打开 Jupyter 笔记本。打开后,创建一个新文件,并将其重命名为“ Week_06。“接下来,对标题为:“字典”的第一个单元格进行降价。“我们将开始在那个牢房下面工作。
什么是字典?
字典是无序数据的集合,存储在键 - 值对中。“无序的意思是它在内存中的存储方式。它不能通过索引访问,而是通过键访问。列表被称为有序数据集合,因为每个项目都被分配了一个特定的位置。字典的工作方式类似于现实生活中的字典,其中关键字是单词,值是定义。字典对于处理大型数据、映射数据、CSV 文件、API、发送或接收数据等非常有用。
声明字典
和其他变量一样,变量名放在等号运算符的左边,右边是字典。所有的字典都是通过使用左花括号和右花括号创建的。在花括号之间,我们定义了我们的键值对。只能用字符串或数字来声明密钥。有一个冒号分隔键和值。冒号后面是值,它可以是任何数据类型,包括其他数据集合,甚至是另一个字典:
# declaring a dictionary variable
empty = { } # empty dictionary
person = { "name": "John Smith" } # dictionary with one key/value pair
customer = {
"name": "Morty",
"age": 26
} # dictionary with two key/value pairs
print(customer)
去查查手机。这里我们可以看到我们声明了三个不同的字典,一个是空的,一个只有一个键值对,另一个有多个键值对。所有键值对必须用逗号分隔。接下来我们将看到如何访问这些数据。
注意
您也可以使用 dict( ) 来声明一个空字典。
访问词典信息
存储在字典中的所有数据都是通过与您试图访问的值相关联的键来访问的。我们简单地写下字典的名字,后面加上方括号。方括号内是密钥。这将检索存储在该项中的值:
# accessing dictionary information through keys
person = { "name": 'John" }
print( person[ "name" ] ) # access information through the key
去查查手机。这将输出“ John ,因为这是存储在“ name 键中的内容。
使用 Get 方法
另一种检索信息的方法是使用 get() 方法。使用这种方法和以前访问值的方法的主要区别在于 get 方法不会抛出键错误。如果键不存在,它将简单地返回“ None ”。您还可以在调用中添加第二个参数,以便让程序返回更具体的数据类型。让我们试试:
# using the get method to access dictionary information
person = { "name": 'John" }
print( person.get("name") ) # retrieves value of name key as before
print( person.get("age", "Age is not available.") ) # get is a secure way to retrieve information
去查查手机。在第二个打印语句中,我们将收到“年龄不可用”消息,因为关键字“年龄不存在。这给了我们一种更安全的检索信息的方法。
带列表的词典
当您开始将数据集合作为值使用时,字典变得非常强大:
# storing a list within a dictionary and accessing it
data = { "sports": [ "baseball", "football", "hockey", "soccer" ] }
print( data["sports"][0] ) # first access the key, then the index
去查查手机。为了访问列表,我们必须首先访问“运动键。之后,我们可以通过索引像访问任何其他列表一样访问项目。这会输出“棒球”。请记住,如果不先附加一个键,我们就无法创建存储列表的字典:
# improperly storing a list within a dictionary
sports = [ "baseball", "football", "hockey", "soccer" ]
sports_dict = dict( sports ) # will produce error, no key
去查查手机。这将产生一个错误,因为没有与 sports 变量相关联的键。要正确存储该列表,您应该编写以下内容:
>>> sports_dict = dict( { "sports" : sports } )
带词典的列表
当试图找出如何访问信息时,字典中的列表组合和反之亦然会变得令人困惑。永远记住列表是有索引的,字典使用关键字。根据存储数据的顺序,您需要先做其中一项。当一个列表存储一个字典时,您需要首先通过索引来访问该字典。之后,您可以访问字典中的键值对。让我们看一个例子:
# storing a dictionary within a list and accessing it
data = [ "John", "Dennis", { "name": "Kirsten" } ]
print( data[2] ) # the dictionary is in index 2
print( data[2]["name"] ) # first access the index, then access the key
去查查手机。首先,我们访问第二个索引中的条目,这是我们的字典。然后我们访问存储在“ name 键中的值,它是“ Kirsten 的输出。
注意
使用数字作为键时要非常小心。
带字典的字典
由于它们在内存中的存储方式,字典非常强大和高效。通常,您会希望使用字典作为键值对的值。让我们看一个例子:
# storing a dictionary within a dictionary and accessing it
data = {
"team": "Boston Red Sox",
"wins": { "2018": 108, "2017": 93 }
}
print( data["wins"] ) # will output the dictionary within the wins key
print( data["wins"]["2018"] ) # first access the wins key, then the next key
去查查手机。这将在第二条语句中输出“ 108 ”。我们可以通过访问“胜”的第一个键,然后访问“ 2018 的第二个键来访问这些信息。
周一练习
-
用户输入:询问用户的姓名和年龄,然后用这些键值对创建一个字典。创建后输出词典。
-
访问配料:使用 for 循环在*“配料”*键内输出以下列表中的所有配料:
>>> pizza = { >>> 'ingredients': ['cheese', 'sausage', 'peppers'] >>> }
数据集合允许我们处理大数据,因为它们存储在键值对中。请记住,数据是通过键访问的。
星期二:使用字典
今天的课程将涵盖如何添加数据、操作数据、移除键值对以及遍历字典。
为了跟上这一课,让我们从我们以前的笔记本文件“ Week_06 ”继续,并在底部简单地添加一个标有“使用字典”的单元格。
添加新信息
在声明一个字典之后,您通常需要添加新的键值对。让我们看看如何:
# adding new key/value pairs to a dictionary
car = { "year": 2018 }
car["color"] = "Blue"
print( "Year: { } \t Color: { }".format( car["year"], car["color"] ) )
去查查手机。要添加新的对,在 equals 操作符的左侧,您需要提供字典名,后跟括号内的新键。右边是你想要的值。这将输出一个带有我们汽车信息的格式良好的字符串。
注意
从 Python 开始,3.7 的字典是默认排序的。在 Python 的旧版本中,键值对并不总是保持它们的顺序。您可能需要使用一个 OrderedDict()。
改变信息
改变键值对就像添加一个新的键值对一样。如果键存在,它简单地覆盖以前的值;但是,如果它不存在,它将为您创建一个新的键-值对:
# updating a value for a key/value pair that already exists
car = { "year": 2018, "color": "Blue" }
car["color"] = "Red"
print( "Year: { } \t Color: { }".format( car["year"], car["color"] ) )
去查查手机。就像我们之前声明一个新的键-值对一样,因为键" color "已经存在于字典中,它只是覆盖了先前的值。
删除信息
有时你需要去掉某一对。为此,您需要使用 del 函数:
# deleting a key/value pair from a dictionary
car = { "year": 2018 }
try:
del car["year"]
print(car)
except:
print("That key does not exist")
去查查手机。删除键值对时要非常小心。如果你试图删除的密钥不存在,它会使程序崩溃。为了避免这个问题,我们使用了 try/except。
循环字典
字典和列表一样是可重复的。然而,他们有三种不同的方法。可以同时迭代键和值,也可以只迭代键或值。
仅循环键
要在只访问键的情况下遍历字典,您将使用*。*键()【方法:
# looping over a dictionary via the keys
person = { "name": "John", "age": 26 }
for key in person.keys( ):
print(key)
print( person[key] ) # will output the value at the current key
去查查手机。当我们迭代 person 时, key 的临时变量将等于每个键名。这仍然使我们能够通过使用我们的键变量来访问每个值。
仅循环值
当不需要访问按键时,使用*。values( )* 方法最好:
# looping over a dictionary via the values
person = { "name": "John", "age": 26 }
for value in person.values( ):
print(value)
去查查手机。我们不能访问键名,但是对于这个方法,我们只是试图获取值。当我们遍历 person 时,我们的临时变量 value 将存储键值对中的每个值。
循环键值对
如果您需要访问键和值的能力,那么您将希望使用。items()方法。这种方法将分配两个临时变量,而不是一个:
# looping over a dictionary via the key/value pair
person = { "name": "John", "age": 26 }
for key, value in person.items( ):
print( "{ }: { }".format(key, value) )
去查查手机。当我们迭代 person 时,键-值对被分配给它们各自的临时变量 key 和值。我们现在很容易接触到这两者。
注意
临时变量名通常称为“ k ”和“ v.
星期二练习
-
用户输入:声明一个空字典。询问用户的姓名、地址和电话号码。将该信息添加到字典中,并遍历它以显示给用户。
-
解题:下面这段代码有什么问题:
>>> person = { 'name', 'John Smith' } >>> print(person['name'])
今天对于理解如何使用字典很重要。记住,添加和改变键值对是相同的语法。
星期三:元组、集、冷冻集
Python 包括几个其他数据集合,它们都有自己的特性。今天,我们将看看另外三个有时有用的方法。
为了跟上这一课,让我们从笔记本文件“ Week_06 ”继续,简单地在底部添加一个 markdown 单元格,表示“元组、集、冷冻集。
什么是元组?
一个元组与一个列表完全相同,除了它是不可变的。当一个东西是不可变的,这意味着它一旦被声明就不能被改变。元组对于存储您不想更改的信息很有用。它们像列表一样排序,所以你可以使用索引遍历它们。
声明元组
要声明一个元组,需要使用逗号来分隔两个或多个条目。列表用外面的方括号表示,而元组可以用可选的括号声明。它们更有可能用括号声明,因为这样更容易阅读。让我们看一个例子:
# declaring a tuple
t1 = ("hello", 2, "hello") # with parens
t2 = True, 1 # without parens
print( type(t1), type(t2) ) # both are tuples
t1[0] = 1 # will crash, tuples are immutable once declared
去查查手机。你可以看到我们输出变量的类型,它们都输出“ tuple ”。如上所述,元组的声明有括号和无括号。该单元格中的最后一行将产生一个错误,因为元组的项一旦声明就不能更改。覆盖元组中数据的唯一方法是重新声明整个元组。
什么是集合?
集合共享列表和字典的相同特征。一个集合是一个类似列表的信息集合;然而,就像字典中的关键字一样,集合只能包含唯一值。它们也是一个无序集合。这意味着它们不能通过索引访问,而是像字典键一样通过值本身访问。但是它们可以被迭代,就像字典键如何循环一样。在存储独特物品的情况下,器械包很实用。
声明集合
有两种方法可以声明一个集合。第一种方法是使用关键字“ set ”,后跟括号和方括号。第二种方式更实用,看起来像是使用一组花括号声明的字典。让我们来看看:
# declaring a set
s1 = set( [1, 2, 3, 1] ) # uses the set keyword and square brackets
s2 = {4, 4, 5} # uses curly brackets, like dictionary
print( type(s1), type(s2) )
s1.add(5) # using the add method to add new items to a set
s1.remove(1) # using the remove method to get rid of the value 1
print(s1) # notice when printed it removed the second "1" at the end
去查查手机。我们将看到它将两个变量的类型输出为“ sets ”。当我们输出我们的 s1 变量的值时,它最终只输出“ 1,2,3 ”。请记住,集合是唯一的项目,因此它会删除第二个 "1" 值。集合有各种方法,允许我们添加、删除和更改其中的信息,如添加/删除行所示。
什么是冰冻人?
Frozensets 本质上是一个集合和一个元组的组合。分别是不可变、无序、唯一。这些对于像银行账号这样的敏感信息来说是完美的,因为你不想改变它们。它们可以被迭代,但不能被索引。
声明一个冷冻集
要声明一个 frozenset,可以使用关键字“ frozenset ”,后跟括号和方括号。这是声明 frozenset 的唯一方法。让我们来看一个例子:
# declaring a frozenset
fset = frozenset( [1, 2, 3, 4] )
print( type(fset) )
去查查手机。在本书中,我们不会经常使用 frozensets,但是所有这些数据集合在 Python 语言中都有特定的用途。
数据收集差异
表 6-1 显示了每个集合之间的差异汇总。
表 6-1
收藏异同
|数据收集
|
整齐的
|
可重复的
|
独一无二的
|
不变的
|
易变的
| | --- | --- | --- | --- | --- | --- | | 目录 | 是 | 是 | 不 | 不 | 是 | | 词典 | 不 | 是 | 仅钥匙 | 仅钥匙 | 仅值 | | 元组 | 是 | 是 | 不 | 是 | 不 | | 一组 | 不 | 是 | 是 | 不 | 是 | | 冻结集合 | 不 | 是 | 是 | 是 | 不 |
周三练习
-
用户输入:要求用户输入任意多的银行账号,并将其存储在一个列表中。一旦用户输入完信息,就将列表转换成 frozenset 并打印出来。
-
转换:将下面的列表转换成一组唯一的值。打印出来后,检查有没有重复:
>>> nums = [3, 4, 3, 7, 10]
今天,我们能够查看其他三个数据集合。每一个都有一个目的,即使我们大部分时间都在使用字典和列表。
星期四:读写文件
根据你编写的程序类型,你需要保存或访问信息。为此,你需要了解如何处理文件,无论是创建、写,还是读。
为了继续本课,让我们从之前的笔记本文件“ Week_06 ”继续,只需在底部添加一个 markdown 单元格,显示“阅读&编写文件”。
使用文本文件
默认情况下,Python 附带了一个 open() 函数,允许我们创建或修改文件。这个函数接受两个参数,文件名,和模式。如果文件名存在,那么它将简单地打开文件进行修改;否则,它将为您创建文件。该模式参考 Python 如何打开和处理文件。例如,如果你只是需要从文件中获取信息,你可以打开它阅读。这将允许您在不意外更改文件的情况下使用它。让我们看看如何打开、写入和读取文本文件:
1| # opening/creating and writing to a text file
2| f = open("test.txt", "w+") # open file in writing and reading mode
3| f.write("this is a test")
4| f.close( )
5| # reading from a text file
6| f = open("test.txt", "r")
7| data = f.read( )
8| f.close( )
9| print(data)
去查查手机。让我们一行一行地走一遍。我们以读写模式打开文件进行完全编辑,并将值赋给变量 f 。在第 3 行,我们使用 write() 方法将我们的句子写入文件。然后我们关闭文件。任何时候你打开一个文件,你都必须关闭它。在我们创建并写入测试文件之后,我们以只读模式打开它。在第 7 行,我们使用 read() 方法将文件的所有内容读入一个字符串,该字符串被分配给我们的数据变量。然后我们输出信息。
注意
模式“w”将覆盖整个文件。使用“a”进行追加。
写入 CSV 文件
CSV 文件通过在每个单元格之间用逗号分隔来处理数据。这就是所谓的表格数据结构。为了开始使用它们,Python 有一个名为“csv”的默认库。为了与他们合作,我们需要导入它。导入这个库之后,我们将使用第二种打开文件的方法,使用带有关键字的**。这个概念就像一个 while 循环,所以当文件打开时,我们可以使用它,一旦代码块运行完毕,它会自动为我们关闭文件。让我们来看看这个例子:**
1| # opening/creating and writing to a csv file
2| import csv
3| with open("test.csv", mode="w", newline="") as f:
4| writer = csv.writer(f, delimiter=",")
5| writer.writerow( ["Name", "City"] )
6| writer.writerow( ["Craig Lou", "Taiwan"] )
去查查手机。让我们一行一行地走一遍。我们在第 2 行导入 CSV 库。然后我们以写模式打开文件,作为变量 f 。我们还将 newline 参数设置为空字符串,这样就不会在行之间创建空行。在第 4 行,我们创建了一个 writer 变量,允许我们写入 CSV 文件。最后两行将几行数据写入 CSV 文件。一旦块完成,文件自动关闭,我们就完成了。继续检查文件;您将看到新的数据输出。请记住,写入模式将始终覆盖文件中先前的任何数据。
从 CSV 文件中读取
为了从我们刚刚创建的 CSV 文件中读取数据,我们可以简单地将模式设置为 read:
1| # reading from csv files
2| with open("test.csv", mode="r") as f:
3| reader = csv.reader(f, delimiter=",")
4| for row in reader:
5| print(row)
去查查手机。您会注意到它将每一行输出为一个列表,其中包含两个条目。我们以读取模式打开文件,作为变量 f 。然后我们通过为我们读取文件内容的 CSV 库创建一个阅读器对象。然后我们循环遍历 reader 变量并打印出每一段数据。
注意
对象将在下一周讨论。
Python 中的文件模式
表 6-2 显示了一些你可以在 Python 中使用的文件模式。
表 6-2
文件模式
|方式
|
描述
| | --- | --- | | r′ | 这是默认模式。它以只读方式打开文件。 | | w ' | 打开文件进行写入。如果文件不存在,它会创建一个。 | | x ' | 创建新文件。如果文件存在,操作将失败。 | | a′ | 以追加模式打开。如果文件不存在,它会创建一个。 | | ' b ' | 以二进制模式打开。 | | '+' | 将打开一个文件进行读写。利于更新。 |
周四练习
-
用户输入:询问用户最喜欢的号码,并保存到文本文件中。
-
数据转储:使用以下数据的字典,将信息保存到一个 csv 文件中,以关键字为头,以值为数据行:
>>> data = { 'name' : ['Dave', 'Dennis', 'Peter', 'Jess'], 'language': ['Python', 'C', 'Java', 'Python'] }
今天我们学习了如何处理文本和 CSV 文件。有两种处理文件的方法,每种方法都有自己的用途,但通常使用 with 语句更容易。
星期五:用 CSV 文件创建用户数据库
对于本周的项目,我们将使用 CSV 文件构建一个用户数据库的副本。我们将能够接受输入,并允许用户登录/注销/注册。
为了继续本课,让我们从之前的笔记本文件“ Week_06 ”继续,并在底部添加一个 markdown 单元格,内容为“星期五项目:使用 CSV 文件创建用户数据库”。
完工图纸
本周的项目都是关于逻辑的。我们需要了解如何设置用户登录和注销的逐步过程。这个程序有三个主要部分,注册用户、用户登录和运行程序的主循环。知道了前两个是任务,我们就可以把它们做成函数,必要时在主循环中调用它们。让我们继续为这个程序设计逻辑流程:
- 检查用户是否登录。
-
如果已登录,询问他们是否愿意注销/退出。
- 退出或注销用户,然后重新启动。
-
否则,询问他们是否愿意登录/注册/退出。
-
如果登录,要求用户输入电子邮件/密码。
-
如果正确,请用户登录并重新启动。
-
否则,显示错误并重启。
-
-
如果注册,要求提供电子邮件/密码/口令 2。
-
如果密码匹配,保存用户并重启。
-
否则,显示错误并重启。
-
-
如果退出,说谢谢并退出程序。
-
-
这是我们主循环的程序流程图。既然您已经确切地知道了程序应该如何运行,我建议您在继续之前尝试自己构建它。通过这样做,你将能够引用我的代码,看到你可能在哪里犯了错误,等等。循环将继续运行,直到用户退出并允许他们注册或登录。登录后,您只能注销或退出。这很简单,但将提供一些关于如何处理菜单系统的见解。
设置必要的导入
首先,让我们从导入运行程序所需的文件和函数开始:
1| # import all necessary packages to be used
2| import csv
3| from IPython.display import clear_output
我们将在一个单元中编写所有的代码,所以现在不需要运行这个单元。我们已经导入了 CSV 库,以便能够处理 CSV 文件,还导入了 clear output 函数,允许我们从单元格中清除笔记本语句。
处理用户注册
接下来,我们将设计注册用户的功能。让我们来看看这个功能:
5| # handle user registration and writing to csv
6| def registerUser( ):
7| with open("users.csv", mode="a", newline="") as f:
8| writer = csv.writer(f, delimiter=",")
10| print("To register, please enter your info:")
11| email = input("E-mail: ")
12| password = input("Password: ")
13| password2 = input("Re-type password: ")
15| clear_output( )
17| if password == password2:
18| writer.writerow( [email, password] )
19| print("You are now registered!")
20| else:
21| print("Something went wrong. Try again.")
我们首先定义函数并打开一个名为“ user.csv ”的 CSV 文件。这将是我们存储数据的文件。我们用该文件创建一个 writer 对象,它将允许我们追加附加数据。在询问用户的信息后,我们检查输入的两个密码是否相同,然后或者用我们创建的 writer 对象添加用户,或者让用户知道出现了错误。您可以随意调用这个函数并试用它。第一次尝试后,您应该会看到文件被创建。
处理用户登录
我们需要设计的第二个任务是让用户登录的能力。让我们看看如何做到这一点:
23| # ask for user info and return true to login or false if incorrect info
24| def loginUser( ):
25| print("To login, please enter your info:")
26| email = input("E-mail: ")
27| password = input("Password: ")
29| clear_output( )
31| with open("users.csv", mode="r") as f:
32| reader = csv.reader(f, delimiter=",")
34| for row in reader:
35| if row == [email, password]:
36| print("You are now logged in!")
37| return True
39| print("Something went wrong, try again.")
40| return False
在用户登录功能中,我们要求用户输入他们的信息。然后,我们以只读模式打开存储用户信息的文件。使用 CSV 库创建一个 reader 对象,我们在第 34 行逐行遍历数据。我们读取的每一行都是包含两项的列表形式。第一项总是电子邮件,第二项是密码。在第 35 行,我们根据一个填充了用户输入信息的临时列表检查行信息。如果数据匹配,我们登录并返回 True 否则,我们告诉他们出错了,并返回 False。注册后尝试调用此函数。
注意
该文件存储在与笔记本文件相同的目录中。
创建主循环
神奇的事情就发生在这里。到目前为止,我们已经创建了程序的两个主要功能,注册和登录用户。这个主循环将处理菜单系统,以及基于用户是否登录来显示什么。让我们继续完成这个程序:
42| # variables for main loop
43| active = True
44| logged_in = False
46| # main loop
47| while active:
48| if logged_in:
49| print("1\. Logout\n2\. Quit")
50| else:
51| print("1\. Login\n2\. Register\n3\. Quit")
53| choice = input("What would you like to do? ").lower( )
55| clear_output( )
57| if choice == "register" and logged_in == False:
58| registerUser( )
59| elif choice == "login" and logged_in == False:
60| logged_in = loginUser( )
61| elif choice == "quit":
62| active = False
63| print("Thanks for using our software!")
64| elif choice == "logout" and logged_in == True:
65| logged_in = False
66| print("You are now logged out.")
67| else:
68| print("Sorry, please try again!")
去查查手机。在循环开始之前,我们为程序定义了几个变量。这些变量将跟踪登录的用户以及程序是否应该继续运行。然后,我们进入主循环,并根据登录的用户显示适当的菜单。由于程序启动时用户从未登录,将显示第二个菜单。然后我们询问用户他们想使用 input() 方法做什么。下一部分是我们菜单系统的逻辑发生的地方。根据用户的选择,我们执行特定的操作。我们已经使用户只能登录或注册,如果他们还没有登录。同样,他们只有在登录后才能注销。如果他们选择登录或注册,我们调用各自的函数来执行他们的操作。为了让用户登录,记住该函数返回真或假,然后我们将 logged_in 变量设置为。如果用户决定退出,我们将我们的活动变量设置为假并退出程序。在此之前,程序将根据登录的用户不断显示正确的菜单。如果他们选择了包含的选项之外的任何选项,我们将显示错误消息。
今天,我们能够理解使用 CSV 文件的用户注册过程背后的逻辑。我们将在本书后面使用类似的概念来存储数据。
每周总结
本周我们学习了更重要的数据收集之一,字典。它们在处理数据时很重要,因为它们允许我们分配键值对并高速检索信息。我们还讨论了一些在特定情况下有用的其他数据收集。在理解了集合之后,我们能够学习使用文件。读写文件让我们能够给程序添加额外的功能,正如我们在周五项目中创建用户注册应用时看到的那样。我们将能够把这些知识应用到我们在本书后面创建的程序中。
挑战问题解决方案
如果你不知道什么是回文,希望你查一下。这是一个单词向前和向后拼写相同的地方,就像“赛车”有几种不同的方法可以得到这个问题的答案。以下是一个简单明了的问题解决方案示例:
>>> def palindrome(word):
>>> return True if word == word[::-1] else False
记得我们在前一章中讨论过三元运算符,它允许我们写一行条件语句。如果您写出了整个 if else 语句,但能够获得相同的结果,那么干得好!展望未来,你应该开始尝试理解如何进一步压缩你的代码,以得到适当的优化。
每周挑战
要测试你的技能,请尝试以下挑战:
|最喜欢的食物?
|
票数
| | --- | --- | | 土耳其 | 5 | | 沙拉 | 3 |
-
更改密码:从周五开始在项目中增加一个名为 changePassword 的功能,允许用户在登录时更改密码。
-
最喜欢的食物:写一个新程序,询问用户他们最喜欢的食物是什么。将答案保存到一个名为“ favorite_food.csv 的 CSV 文件中。回答后,显示一个记录结果的表格。表格示例: