文章目录
- 第一部分 基础知识
- 第1章 搭建环境
- 第2章 变量和简单数据类型
- 第 3 章 列表简介
- 第 4 章 操作列表
- 第 5 章 if 语句
- 第 6 章 字典
- 第 7 章 用户输入和while 循环
- 第 8 章 函数
- 第 9 章 类
- 第 10 章 文件和异常
第一部分 基础知识
第1章 搭建环境
略
第2章 变量和简单数据类型
2.1 运行hello_world.py时发生的情况
hello_world.py
>>> print("Hello Python world!")
Hello Python world!
2.2 变量
>>> message = "Hello Python world!"
>>> print(message)
Hello Python world!
2.2.1 变量的命名和使用
变量使用的规则:
1.变量名只能包含字母、数字和下划线。变量名可以字母或下划线打头,但不能以数字打头,例如,可将变量命名为message_1,但不能将其命名为1_message。
2.变量名不能包含空格,但可使用下划线来分隔其中的单词。例如,变量名greeting_message可行,但变量名greeting message会引发错误。
3.不要将Python关键字和函数名用作变量名,即不要使用Python保留用于特殊用途的单词,如print (请参见附录A.4)。
4.变量名应既简短又具有描述性。例如,name比n好,student_name比s_n好,name_length比length_of_persons_name好。
5.慎用小写字母l和大写字母O,因为它们可能被人错看成数字1和0。
2.2.2 使用变量时避免命名错误
>>> message = "Hello Python Crash Course
reader!"
>>> print(mesage)
Traceback (most recent call last):
File
"<pyshell#29>", line 1, in <module>
print(mesage)
NameError: name 'mesage' is not defined
2.3 字符串
字符串 就是一系列字符。在Python中,用引号括起的都是字符串,其中的引号可以是单引号,也可以是双引号。
>>> "This is a string."
'This is a string.'
>>> 'This is also a string.'
'This is also a string.'
>>> 'I told my friend, "Python is my
favorite language!"' "The language 'Python' is named after Monty
Python, not the snake." "One of Python's strengths is its diverse and
supportive community."
'I told my friend, "Python is my favorite
language!"The language \'Python\' is named after Monty Python, not the
snake.One of Python\'s strengths is its diverse and supportive community.'
>>>
2.3.1 使用方法修改字符串的大小写
>>> name = "ada lovelace"
>>> print(name.title())
#title() 以首字母大写的方式显示每个单词,即将每个单词的首字母都改为大写。
Ada Lovelace
>>> name = "Ada Lovelace"
>>> print(name.upper()) #将字符串改为全部大写
ADA LOVELACE
>>> print(name.lower()) #将字符串改为全部小写
ada lovelace
2.3.2 合并(拼接)字符串
>>> first_name = "ada"
>>> last_name = "lovelace"
>>> full_name = first_name + " " +
last_name
>>> print(full_name)
ada lovelace
Python使用加号(+ )来合并字符串。在这个示例中,我们使用+ 来合并first_name 、空格和last_name 。
first_name = "ada"
last_name = "lovelace"
full_name = first_name + " " + last_name
message = "Hello, " + full_name.title() +
"!"
print(message)
Hello, Ada Lovelace!
2.3.3 使用制表符或换行符来添加空白
要在字符串中添加制表符,可使用字符组合\t
>>> print("Python")
Python
>>> print("\tPython")
Python
要在字符串中添加换行符,可使用字符组合\n :
>>>
print("Languages:\nPython\nC\nJavaScript")
Languages:
Python
C
JavaScript
还可在同一个字符串中同时包含制表符和换行符。字符串"\n\t" 让Python换到下一行,并在下一行开头添加一个制表符。
>>>
print("Languages:\n\tPython\n\tC\n\tJavaScript")
Languages:
Python
C
JavaScript
2.3.4 删除空白
>>> favorite_language = 'python '
>>> favorite_language
'python '
>>> favorite_language.rstrip()#。对变
量favorite_language 调用方法rstrip() 后,这个多余的空格被删除了。然而,这种删除只是暂时的,接下来再次询问favorite_language 的值时,你会发 现这个字符串与输入时一样,依然包含多余的空白
'python'
>>> favorite_language
'python '
还可以剔除字符串开头的空白,或同时剔除字符串两端的空白。为此,可分别使用方法lstrip() 和strip()
:
>>> favorite_language = ' python '
>>> favorite_language.rstrip()
' python'
>>> favorite_language.lstrip()
'python '
>>> favorite_language.strip()
'python'
2.3.5 使用字符串时避免语法错误
>>> message = "One of Python's strengths is
its diverse community." #撇号位于两个双引号之间,因此Python解释器能够正确地理解这个字符串
>>> print(message)
One of Python's strengths is its diverse community.
>>> message = 'One of Python's strengths is its
diverse community.' #如果你使用单引号,Python将无法正确地确定字符串的结束位置
SyntaxError: invalid syntax
练习:
2-7 剔除人名中的空白: 剔除人名中的空白: 存储一个人名,并在其开头和末尾都包含一些空白字符。务必至少使用字符组合"\t" 和"\n"
各一次。 打印这个人名,以显示其开头和末尾的空白。然后,分别使用剔除函数lstrip() 、rstrip() 和strip()
对人名进行处理,并将结果打印出来。
>>> name = " Faker \t\n"
>>> print(name)
Faker
>>> print(name.lstrip())
Faker
>>> print(name.rstrip())
Faker
>>> print(name.strip())
Faker
2.4 数字
2.4.1 整数
在Python中,可对整数执行加(+ )减(- )乘(* )除(/ )运算。
>>> 3 / 2 #表示正常除法
1.5
>>> 3 // 2 #表示取整除法
1
>>> 3 ** 2
9
2.4.2 浮点数
需要注意的是,结果包含的小数位数可能是不确定的:
>>> 0.2 + 0.1
0.30000000000000004
>>> 3 * 0.1
0.30000000000000004
2.4.3 使用函数str() 避免类型错误
>>> age = 23
>>> message = "Happy " + age +
"rd Birthday!"
Traceback (most recent call last):
File
"<pyshell#76>", line 1, in <module>
message =
"Happy " + age + "rd Birthday!"
TypeError: can only concatenate str (not "int")
to str
这是一个类型错误,意味着Python无法识别你使用的信息。在这个示例中,Python发现你使用了一个值为整数(int )的变量。Python知道,这个变量表示的可能是数值23,也可能是字符2和3。像上面这样在字符串中使用整数时,需要显式地指出你希望Python将这个整数用作字符串。为此,可调用函数str() , 它让Python将非字符串值表示为字符串:
>>> age = 23
>>> message = "Happy " + str(age) +
"rd Birthday!"
>>> print(message)
Happy 23rd Birthday!
2.5 注释
2.5.1 如何编写注释
在Python中,注释用井号(# )标识。井号后面的内容都会被Python解释器忽略
2.5.2 该编写什么样的注释
编写注释的主要目的是阐述代码要做什么,以及是如何做的。在开发项目期间,你对各个部分如何协同工作了如指掌,但过段时间后,有些细节你可能不记得了。当然,你总是 可以通过研究代码来确定各个部分的工作原理,但通过编写注释,以清晰的自然语言对解决方案进行概述,可节省很多时间。
要成为专业程序员或与其他程序员合作,就必须编写有意义的注释。当前,大多数软件都是合作编写的,编写者可能是同一家公司的多名员工,也可能是众多致力于同一个开源 项目的人员。训练有素的程序员都希望代码中包含注释,因此你最好从现在开始就在程序中添加描述性注释。作为新手,最值得养成的习惯之一是,在代码中编写清晰、简洁的 注释。
如果不确定是否要编写注释,就问问自己,找到合理的解决方案前,是否考虑了多个解决方案。如果答案是肯定的,就编写注释对你的解决方案进行说明吧。相比回过头去再添 加注释,删除多余的注释要容易得多。从现在开始,本书的示例都将使用注释来阐述代码的工作原理。
2.6 Python之禅
>>> import this
The Zen of Python, by Tim Peters
Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious
way to do it.
Although that way may not be obvious at first unless
you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad
idea.
If the implementation is easy to explain, it may be a
good idea.
Namespaces are one honking great idea -- let's do more of
those!
2.7 小结
第 3 章 列表简介
3.1 列表是什么
列表 由一系列按特定顺序排列的元素组成。你可以创建包含字母表中所有字母、数字0~9或所有家庭成员姓名的列表;也可以将任何东西加入列表中,其中的元素之间可以没有任何关系。
在Python中,用方括号([] )来表示列表,并用逗号来分隔其中的元素。下面是一个简单的列表示例,这个列表包含几种自行车:
>>> bicycles = ['trek', 'cannondale', 'redline', 'specialized']
>>> print(bicycles)
['trek', 'cannondale', 'redline', 'specialized']
3.1.1 访问列表元素
列表是有序集合,因此可以按索引访问列表中的元素。
>>> bicycles = ['trek', 'cannondale', 'redline', 'specialized']
>>> print(bicycles[0]) #打印列表中第一个元素
trek
>>> bicycles = ['trek', 'cannondale', 'redline', 'specialized']
>>> print(bicycles[0])
trek
>>> print(bicycles[0].title()) #使用上一章的title()方法使格式更加好看
Trek
3.1.2 索引从0而不是而不是1开始开始
>>> bicycles = ['trek', 'cannondale', 'redline', 'specialized']
>>> print(bicycles[1])
cannondale
>>> print(bicycles[3])
specialized
>>> print(bicycles[-1]) #访问最后一个列表元素可以通过将索引指定为-1
specialized
3.1.3 使用列表中的各个值
>>> bicycles = ['trek', 'cannondale', 'redline', 'specialized']
>>> message = "My first bicycle was a "+ bicycles[0].title() + "."
>>> print(message)
My first bicycle was a Trek.
3.2 修改、添加和删除元素
3.2.1 修改列表元素
要修改列表元素,可指定列表名和要修改的元素的索引,再指定该元素的新值。
>>> motorcycles = ['honda', 'yamaha', 'suzuki']
>>> print(motorcycles)
['honda', 'yamaha', 'suzuki']
>>> motorcycles[0] = 'ducati'
>>> print(motorcycles)
['ducati', 'yamaha', 'suzuki']
3.2.2 在列表中添加元素
1. 在列表末尾添加元素
>>> motorcycles = ['honda', 'yamaha', 'suzuki']
>>> print(motorcycles)
['honda', 'yamaha', 'suzuki']
>>> motorcycles.append('ducati') #append可以再列表末尾添加元素
>>> print(motorcycles)
['honda', 'yamaha', 'suzuki', 'ducati']
>>> motorcycles = []
>>> motorcycles.append('honda')
>>> motorcycles.append('yamaha')
>>> motorcycles.append('suzuki')
>>> print(motorcycles)
['honda', 'yamaha', 'suzuki']
2. 在列表中插入元素
使用方法insert() 可在列表的任何位置添加新元素。为此,你需要指定新元素的索引和值。
>>> motorcycles = ['honda','yamaha','suzuki']
>>> motorcycles.insert(0,'ducati') #在第0个位置插入‘ducati’
>>> print(motorcycles)
['ducati', 'honda', 'yamaha', 'suzuki']
3.2.3 从列表中删除元素
1. 使用 使用del 语句删除元素
>>> motorcycles = ['honda','yamaha','suzuki']
>>> print(motorcycles)
['honda', 'yamaha', 'suzuki']
>>> del motorcycles[0] #删除第0个元素,注意del用法
>>> print(motorcycles)
['yamaha', 'suzuki']
2. 使用方法 使用方法pop() 删除元素 删除元素
方法pop() 可删除列表末尾的元素,并让你能够接着使用它。术语弹出 弹出 (pop)源自这样的类比:列表就像一个栈,而删除列表末尾的元素相当于弹出栈顶元素。
>>> motorcycles = ['honda','yamaha','suzuki']
>>> print(motorcycles)
['honda', 'yamaha', 'suzuki']
>>> popped_motorcycles = motorcycles.pop() #将出栈元素保存起来
>>> print(motorcycles) #打印弹出元素后的列表
['honda', 'yamaha']
>>> print(popped_motorcycles) #出栈元素仍然能够被访问
suzuki
3. 弹出列表中任何位置处的元素 弹出列表中任何位置处的元素
可以使用pop() 来删除列表中任何位置的元素,只需在括号中指定要删除的元素的索引即可。
>>> motorcycles = ['honda', 'yamaha', 'suzuki']
>>> first_owned = motorcycles.pop(0) #弹出第0个元素
>>> print('The first motorcycle I owned was a ' + first_owned.title() + '.')
The first motorcycle I owned was a Honda.
4. 根据值删除元素
不知道要从列表中删除的值所处的位置。如果你只知道要删除的元素的值,可使用方法remove() 。
假设我们要从列表motorcycles 中删除值’ducati’ 。
>>> motorcycles = ['honda', 'yamaha', 'suzuki', 'ducati']
>>> motorcycles.remove('ducati') #删除元素‘ducati’
>>> print(motorcycles)
['honda', 'yamaha', 'suzuki']
使用remove() 从列表中删除元素时,也可接着使用它的值。
>>> motorcycles = ['honda', 'yamaha', 'suzuki', 'ducati']
>>> print(motorcycles)
['honda', 'yamaha', 'suzuki', 'ducati']
>>> too_expensive = 'ducati'
>>> motorcycles.remove(too_expensive)
>>> print(motorcycles)
['honda', 'yamaha', 'suzuki']
>>> print("\nA " + too_expensive.title() + "is too expensive for me")
A Ducatiis too expensive for me
注意方法remove() 只删除第一个指定的值。如果要删除的值可能在列表中出现多次,就需要使用循环来判断是否删除了所有这样的值。
3.3 组织列表
3.3.1 使用方法sort()对列表进行永久性排序
Python方法sort() 让你能对列表进行排序。
>>> cars = ['bmw','audi','toyata','subaru']
>>> cars.sort()
>>> cars
['audi', 'bmw', 'subaru', 'toyata']
>>> cars = ['bmw','audi','toyota','subaru']
>>> cars.sort(reverse = True) #逆序
>>> cars
['toyota', 'subaru', 'bmw', 'audi']
3.3.2 使用函数sorted() 对列表进行临时排序
要保留列表元素原来的排列顺序,同时以特定的顺序呈现它们,可使用函数sorted()
>>> cars = ['bmw','audi','toyota','subaru']
>>> print('Here is the original list: ')
Here is the original list:
>>> print(cars)
['bmw', 'audi', 'toyota', 'subaru']
>>> print('\nHere is the sorted list:')
Here is the sorted list:
>>> print(sorted(cars))
['audi', 'bmw', 'subaru', 'toyota']
注意,调用函数sorted() 后,列表元素的排列顺序并没有变。如果你要按与字母顺序相反的顺序显示列表,也可向函数sorted() 传递参数reverse=True 。
3.3.3 倒着打印列表
>>> cars = ['bmw','audi','toyota','subaru']
>>> print(cars)
['bmw', 'audi', 'toyota', 'subaru']
>>> cars.reverse() #注意,reverse() 不是指按与字母顺序相反的顺序排列列表元素,而只是反转列表元素的排列顺序
>>> cars
['subaru', 'toyota', 'audi', 'bmw']
方法reverse() 永久性地修改列表元素的排列顺序,但可随时恢复到原来的排列顺序,为此只需对列表再次调用reverse() 即可。
3.3.4 确定列表的长度
使用函数len() 可快速获悉列表的长度。
>>> cars = ['bmw','audi','toyota','subaru']
>>> len(cars)
4
3.4 使用列表时避免索引错误
刚开始使用列表时,经常会遇到一种错误。假设你有一个包含三个元素的列表,却要求获取第四个元素:
>>> motorcycles = ['honda','yamaha','suzuki']
>>> print(motorcycles[3])
Traceback (most recent call last):
File "<pyshell#25>", line 1, in <module>
print(motorcycles[3])
IndexError: list index out of range
注意 发生索引错误却找不到解决办法时,请尝试将列表或其长度打印出来。列表可能与你以为的截然不同,在程序对其进行了动态处理时尤其如此。通过查看列表 或其包含的元素数,可帮助你找出这种逻辑错误。
3.5 小结
第 4 章 操作列表
4.1 遍历整个列表
下面使用for 循环来打印魔术师名单中的所有名字:
>>> magicians = ['alice','david','carolina']
>>> for magician in magicians:
print(magician)
alice
david
carolina
4.1.1 深入地研究循环
没有i的迭代(i = i + 1)
4.1.2 在for 循环中执行更多的操作
>>> magicians = ['alice', 'david', 'carolina']
>>> for magician in magicians:
print(magician.title() + ",that was a great trick!")
Alice,that was a great trick!
David,that was a great trick!
Carolina,that was a great trick!
在for 循环中,想包含多少行代码都可以。在代码行for magician in magicians 后面,每个缩进的代码行都是循环的一部分,且将针对列表中的每个值都执行一次。因 此,可对列表中的每个值执行任意次数的操作。
>>> magicians = ['alice','david','carolina']
>>> for magician in magicians:
print(magician.title() + ",that was a great trick!")
print("I can't wait to see your next trick," + magician.title() + ".\n")
Alice,that was a great trick!
I can't wait to see your next trick,Alice.
David,that was a great trick!
I can't wait to see your next trick,David.
Carolina,that was a great trick!
I can't wait to see your next trick,Carolina.
4.1.3 在for 循环结束后执行一些操作
magicians = ['alice','dacid','carolina']
for magician in magicians:
print(magician.title() + ",that was a great trick!")
print("I can't wait to see your next trick, " +magician.title() + ".\n")
print("Thank you,everyone.That was a great magic show!")
输出:
Alice,that was a great trick!
I can’t wait to see your next trick, Alice.
Dacid,that was a great trick!
I can’t wait to see your next trick, Dacid.
Carolina,that was a great trick!
I can’t wait to see your next trick, Carolina.
Thank you,everyone.That was a great magic show!
4.2 避免缩进错误
4.2.1 忘记缩进
>>> for magician in magicians:
print(magician)
SyntaxError: expected an indented block
4.2.2 忘记缩进额外的代码行
magicians = ['alice','dicid','aerolina']
for magician in magicians:
print(magician.title() + ", that was a great trick!")
print("I can't wait to see your next trick, " + magician.title() + ".\n")
输出:
Alice, that was a great trick!
Dicid, that was a great trick!
Aerolina, that was a great trick!
I can’t wait to see your next trick, Aerolina.
4.2.3 不必要的缩进
message = "Hello Python world!"
print(message)
输出:
File “”, line 2
print(message)
^
IndentationError: unexpected indent
4.2.4 循环后不必要的缩进
magicians = ['alice', 'david', 'carolina']
for magician in magicians:
print(magician.title() + ", that was a great trick!")
print("I can't wait to see your next trick, " + magician.title() + ".\n")
print("Thank you everyone, that was a great magic show!")
输出:
Alice, that was a great trick!
I can’t wait to see your next trick, Alice.
Thank you everyone, that was a great magic show!
David, that was a great trick!
I can’t wait to see your next trick, David.
Thank you everyone, that was a great magic show!
Carolina, that was a great trick!
I can’t wait to see your next trick, Carolina.
Thank you everyone, that was a great magic show!
所有输出全部循环。
4.2.5 遗漏了冒号
magicians = ['alice', 'david', 'carolina']
for magician in magicians
print(magician)
输出:
File “”, line 2
for magician in magicians
^
SyntaxError: invalid syntax
4.3 创建数值列表
4.3.1 使用函数range()
for value in range(1,5):
print(value)
输出:
1
2
3
4
range()左闭右开。
4.3.2 使用range() 创建数字列表
要创建数字列表,可使用函数list() 将range() 的结果直接转换为列表。如果将range() 作为list() 的参数,输出将为一个数字列表。
numbers = list(range(1,5))
numbers
输出:
[1, 2, 3, 4]
使用函数range() 时,还可指定步长。例如,下面的代码打印1~10内的偶数:
even_numbers = list(range(2,11,2))
print(even_numbers)
输出:
[2, 4, 6, 8, 10]
range(起始数字,结束数字,步长)
squares = []
for value in range(1,11):
square = value ** 2
squares.append(square)
print(squares)
输出:
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
4.3.3 对数字列表执行简单的统计计算
digits = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
print(min(digits))
print(max(digits))
print(sum(digits))
输出:
0
9
45
4.3.4 列表解析
列表解析将for循环和创建新元素的代码合并成一行,并自动附加新元素。
squares = [value ** 2 for value in range(1,11)]
print(squares)
输出:
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
要使用这种语法,首先指定一个描述性的列表名,如squares ;然后,指定一个左方括号,并定义一个表达式,用于生成你要存储到列表中的值。在这个示例中,表达式 为value2 ,它计算平方值。接下来,编写一个for 循环,用于给表达式提供值,再加上右方括号。在这个示例中,for 循环为for value in range(1,11) ,它将值 1~10提供给表达式value2 。请注意,这里的for 语句末尾没有冒号。
4.4 使用列表的一部分
4.4.1 切片
players = ['charles', 'martina', 'michael', 'florence', 'eli']
print(players[0:3]) #从第0个到第2个,左闭右开
输出:
[‘charles’, ‘martina’, ‘michael’]
如果你没有指定第一个索引,Python将自动从列表开头开始:
players = ['charles', 'martina', 'michael', 'florence', 'eli']
print(players[:4])
输出:
[‘charles’, ‘martina’, ‘michael’, ‘florence’]
要让切片终止于列表末尾,也可使用类似的语法。
players = ['charles', 'martina', 'michael', 'florence', 'eli']
print(players[1:])
输出:
[‘martina’, ‘michael’, ‘florence’, ‘eli’]
无论列表多长,这种语法都能够让你输出从特定位置到列表末尾的所有元素。本书前面说过,负数索引返回离列表末尾相应距离的元素,因此你可以输出列表末尾的任何切片。
players = ['charles', 'martina', 'michael', 'florence', 'eli']
print(players[-3:]) #返回距离列表末尾元素为3的元素开始到最后元素
输出:
[‘michael’, ‘florence’, ‘eli’]
4.4.2 遍历切片
如果要遍历列表的部分元素,可在for 循环中使用切片。
players = ['charles', 'martina', 'michael', 'florence', 'eli']
print("Here are the first three players on my team:")
for player in players[:3]:
print(player.title())
输出:
Here are the first three players on my team:
Charles
Martina
Michael
4.4.3 复制列表
要复制列表,可创建一个包含整个列表的切片,方法是同时省略起始索引和终止索引([:] )。
my_foods = ['pizza','falafel','carrot cake']
friend_foods = my_foods[:]
print("My favorite foods are:")
print(my_foods)
print("\nMy friend's favorite foods are:")
print(friend_foods)
输出:
My favorite foods are:
[‘pizza’, ‘falafel’, ‘carrot cake’]
My friend’s favorite foods are:
[‘pizza’, ‘falafel’, ‘carrot cake’]
倘若只是简单地将my_foods 赋给friend_foods ,就不能得到两个列表。
my_foods = ['pizza', 'falafel', 'carrot cake']
friend_foods = my_foods #并非两个列表,两个变量指向同一个列表,输出时两个两个列表结果相同
my_foods.append('cannoli')
friend_foods.append('ice cream')
print("My favorite foods are:")
print(my_foods)
print("\nMy friend's favorite foods are:")
print(friend_foods)
输出:
My favorite foods are:
[‘pizza’, ‘falafel’, ‘carrot cake’, ‘cannoli’, ‘ice cream’]
My friend’s favorite foods are:
[‘pizza’, ‘falafel’, ‘carrot cake’, ‘cannoli’, ‘ice cream’]
4.5 元组
元组看起来犹如列表,但使用圆括号而不是方括号来标识。定义元组后,就可以使用索引来访问其元素,就像访问列表元素一样。
4.5.1 定义元组
dimensions = (200,50)
print(dimensions[0])
print(dimensions[1])
输出:
200
50
dimensions = (200,50)
dimensions[0] = 250 #元祖中的值不能被修改
print(dimensions[0])
输出:
TypeError Traceback (most recent call last)
in ()
1 dimensions = (200,50)
----> 2 dimensions[0] = 250
3 print(dimensions[0])
TypeError: ‘tuple’ object does not support item assignment
4.5.2 遍历元组中的所有值
dimensions = (200,50)
for dimension in dimensions: #使用for循环来遍历tuple
print(dimension)
输出:
200
50
4.5.3 修改元组变量
虽然不能修改元组的元素,但可以给存储元组的变量赋值。
dimensions = (200,50)
print("Original dimensions:")
for dimension in dimensions:
print(dimension)
dimensions = (400,100)
print("\nModified dimensions:")
for dimension in dimensions:
print(dimension)
输出:
Original dimensions:
200
50
Modified dimensions:
400
100
相比于列表,元组是更简单的数据结构。如果需要存储的一组值在程序的整个生命周期内都不变,可使用元组。
4.6 设置代码格式
4.6.1 格式设置指南
提出Python语言修改建议,需要编写Python改进提案
4.6.2 缩进
4.6.3 行长
4.6.4 空行
要将程序的不同部分分开,可使用空行。
4.6.5 其他格式设置指南
4.7 小结
第 5 章 if 语句
5.1 一个简单示例
cars = ['audi','bmw','subaru','toyota']
for car in cars:
if car == 'bmw':
print(car.upper())
else:
print(car.title())
输出:
Audi
BMW
Subaru
Toyota
5.2 条件测试
每条if 语句的核心都是一个值为True 或False 的表达式,这种表达式被称为条件测试 条件测试 。Python根据条件测试的值为True 还是False 来决定是否执行if 语句中的代码。如果 条件测试的值为True ,Python就执行紧跟在if 语句后面的代码;如果为False ,Python就忽略这些代码。
5.2.1 检查是否相等
使用相等运算符==,检查==两端的值是否相等,在它两边的值相等时返回True ,否则返回False 。
5.2.2 检查是否相等时不考虑大小写
两个大小写不同的值会被视为不相等。
5.2.3 检查是否不相等
要判断两个值是否不等,可结合使用惊叹号和等号(!= ),,其中的惊叹号表示不 。
5.2.4 比较数字
条件语句中可包含各种数学比较,如小于、小于等于、大于、大于等于。
5.2.5 检查多个条件
1. 使用and 检查多个条件
要检查是否两个条件都为True ,可使用关键字and 将两个条件测试合而为一;如果每个测试都通过了,整个表达式就为True ;如果至少有一个测试没有通过,整个表达式就 为False 。
2. 使用or 检查多个条件
关键字or 也能够让你检查多个条件,但只要至少有一个条件满足,就能通过整个测试。仅当两个测试都没有通过时,使用or 的表达式才为False 。
5.2.6 检查特定值是否包含在列表中
要判断特定的值是否已包含在列表中,可使用关键字in 。
requested_toppings = ['mushrooms','onions','pineapple']
'mushrooms' in requested_toppings
输出:
True
5.2.7 检查特定值是否不包含在列表中
banned_user = ['andrew','carolina','david']
user ='marie'
if user not in banned_user:
print(user.title() + ", you can post a response if you wish.")
输出:
Marie, you can post a response if you wish.
5.2.8 布尔表达式
5.3 if 语句
5.3.1 简单的if语句
age = 19
if age >=18:
print("You are old enough to NetBar!") #符合条件时输出这句话,不符时什么也不做
输出:
You are old enough to NetBar!
5.3.2 if-else 语句
age = 17
if age >=18:
print("You are old enough to NetBar!")
else:
print("Get out,Shit child!")
输出:
Get out,Shit child!
5.3.3 if-elif-else 结构
age = 12
if age < 4:
print("Your admission cost is $0!")
elif age <18:
print("Your admission cost is $5!")
else:
print("Your admission cost is $10!")
输出:
Your admission cost is $5!
5.3.4 使用多个elif 代码块
5.3.5 省略else代码块
age = 12
if age < 4:
price = 0
elif age < 18:
price = 5
elif age < 65:
price = 10
elif age >= 65:
price = 5
print("Your admission cost is $" + str(price) + ".")
输出:
Your admission cost is $5.
5.3.6 测试多个条件
if-elif-else 结构功能强大,但仅适合用于只有一个条件满足的情况:遇到通过了的测试后,Python就跳过余下的测试。这种行为很好,效率很高,让你能够测试一个特定的条件。
然而,有时候必须检查你关心的所有条件。
requested_toppings = ['mushrooms', 'extra cheese']
if 'mushrooms' in requested_toppings:
print("Adding mushrooms.")
if 'pepperoni' in requested_toppings:
print("Adding pepperoni.")
if 'extra cheese' in requested_toppings:
print("Adding extra cheese.")
print("\nFinished making your pizza!")
输出:
Adding mushrooms.
Adding extra cheese.
Finished making your pizza!
alien_color = 'green'
if alien_color == 'green' :
print("You have score five!")
elif: #**注意elif和else的区别,elif后面必须要跟条件,else不用加**
print("You have score ten!")
输出:
File “”, line 4
elif:
^
SyntaxError: invalid syntax
5.4 使用if 语句处理列表
5.4.1 检查特殊元素
requested_toppings = ['mushrooms','green peppers','extra cheese']
for requested_topping in requested_toppings:
if requested_topping == 'green peppers':
print("Sorry, we are out of green peppers right now.")
else:
print("Adding " + requested_topping + ".")
print("\nFinished making your pizza!")
输出:
Adding mushrooms.
Sorry, we are out of green peppers right now.
Adding extra cheese.
Finished making your pizza!
5.4.2 确定列表不是空的
在if 语句中将列表名用在条件表达式中 时,Python将在列表至少包含一个元素时返回True ,并在列表为空时返回False 。
requested_toppings = []
if requested_toppings: #如果列表不为空,则执行以下内容,否则执行else
for requested_topping in requested_toppings:
print("Adding " + requested_topping + ".")
print("\nFinished making your pizza!")
else:
print("Are you sure you want a plain pizza?")
输出:
Are you sure you want a plain pizza?
5.4.3 使用多个列表
available_toppings = ['mushrooms', 'olives', 'green peppers','pepperoni', 'pineapple', 'extra cheese']
requested_toppings = ['mushrooms', 'french fries', 'extra cheese']
for requested_topping in requested_toppings:
if requested_topping in available_toppings:
print("Adding " + requested_topping + ".")
else:
print("Sorry, we don't have " + requested_topping + ".")
print("\nFinished making your pizza!")
输出:
Adding mushrooms.
Sorry, we don’t have french fries.
Adding extra cheese.
5.5 设置if 语句的格式
本章的每个示例都展示了良好的格式设置习惯。在条件测试的格式设置方面,PEP 8提供的唯一建议是,在诸如== 、>= 和<= 等比较运算符两边各添加一个空格,例如,if age < 4: 要比if age<4: 好。
5.6 小结
第 6 章 字典
6.1 一个简单的字典
alien_0 = {'color':'green','points':5}
print(alien_0['color'])
print(alien_0['points'])
输出:
green
5
6.2 使用字典
在Python中,字典是一系列键—值对。每个键都与一个值相关联,你可以使用键来访问与之相关联的值。与键相关联的值可以是数字、字符串、列表乃至字典。事实上,可将任何Python对象用作字典中的值。
在Python中,字典用放在花括号{} 中的一系列键—值对表示,如前面的示例所示:
键—值对是两个相关联的值。指定键时,Python将返回与之相关联的值。键和值之间用冒号分隔,而键—值对之间用逗号分隔。在字典中,你想存储多少个键—值对都可以。 最简单的字典只有一个键—值对,如下述修改后的字典alien_0 所示:
alien_0 = {'color': 'green'}
6.2.1 访问字典中的值
要获取与键相关联的值,可依次指定字典名和放在方括号内的键,如下所示:
alien_0 = {'color':'green'}
print(alien_0['color'])
输出:
green
6.2.2 添加键—值对
字典是一种动态结构,可随时在其中添加键—值对。要添加键—值对,可依次指定字典名、用方括号括起的键和相关联的值。
alien_0 = {'color':'green','point':5}
print(alien_0)
alien_0['x_position'] = 0
alien_0['y_position'] = 25
print(alien_0)
输出:
{‘point’: 5, ‘color’: ‘green’}
{‘x_position’: 0, ‘point’: 5, ‘y_position’: 25, ‘color’: ‘green’}
6.2.3 先创建一个空字典
有时候,在空字典中添加键—值对是为了方便,而有时候必须这样做。为此,可先使用一对空的花括号定义一个字典,再分行添加各个键—值对。
alien_0 = {}
alien_0['color'] = 'green'
alien_0['point'] = 5
print(alien_0)
输出:
{‘point’: 5, ‘color’: ‘green’}
6.2.4 修改字典中的值
要修改字典中的值,可依次指定字典名、用方括号括起的键以及与该键相关联的新值。
alien_0 = {'color':'green'}
print("The alien is " + alien_0['color'] + ".")
alien_0['color'] = 'yellow'
print("The alien is now " + alien_0['color'] + ".")
输出:
The alien is green.
The alien is now yellow.
alien_0 = {'x_position':0,'y_position':25,'speed':'medium'}
print("Original x_position: " + str(alien_0['x_position']))
#向右移动外星人
#根据外星人当前速度决定将其移动多远
if alien_0['speed'] == 'slow':
x_increment = 1
elif alien_0['speed'] == 'medium':
x_increment = 2
else:
x_increment = 3
alien_0['x_position'] = alien_0['x_position'] + x_increment
print("New x_position: " + str(alien_0['x_position']))
输出:
Original x_position: 0
New x_position: 2
6.2.5 删除键—值对
对于字典中不再需要的信息,可使用del语句将相应的键—值对彻底删除。使用del 语句时,必须指定字典名和要删除的键。
alien_0 = {'color': 'green', 'points': 5}
print(alien_0)
del alien_0['points'] #指定字典名alien_0和要删除的键‘points’
print(alien_0)
输出:
{‘points’: 5, ‘color’: ‘green’}
{‘color’: ‘green’}
6.2.6 由类似对象组成的字典
在前面的示例中,字典存储的是一个对象(游戏中的一个外星人)的多种信息,但你也可以使用字典来存储众多对象的同一种信息。
favorite_languages = {
'jen': 'python',
'sarah': 'c',
'edward': 'ruby',
'phil': 'python',
}
print("Sarah's favorite language is " +
favorite_languages['sarah'].title() +
".")
输出:
Sarah’s favorite language is C.
正如你看到的,我们将一个较大的字典放在了多行中。其中每个键都是一个被调查者的名字,而每个值都是被调查者喜欢的语言。确定需要使用多行来定义字典时,在输入左花括号后按回车键,再在下一行缩进四个空格,指定第一个键—值对,并在它后面加上一个逗号。此后你再次按回车键时,文本编辑器将自动缩进后续键—值对,且缩进量与第一个键—值对相同。
练习:
numbers = {
'Tom':5,
'Jack':6,
'Lisa':4,
'Mike':1,
'我':20
}
for name,num in numbers.items():
print(name,"最喜欢的数字是:",num)
输出:
Tom 最喜欢的数字是: 5
Jack 最喜欢的数字是: 6
我 最喜欢的数字是: 20
Mike 最喜欢的数字是: 1
Lisa 最喜欢的数字是: 4
6.3 遍历字典
6.3.1 遍历所有的键—值对
可以使用一个for 循环和**方法items()**来遍历字典:
user_0 = {
'username': 'efermi',
'first': 'enrico',
'last': 'fermi',
}
for key, value in user_0.items():
#用于遍历字典的for 循环,可声明两个变量,用于存储键—值对中的键和值。
#对于这两个变量,可使用任何名称。for k, v in user_0.items() 完全可以
print("\nKey: " + key)
print("Value: " + value)
输出:
Key: username
Value: efermi
Key: first
Value: enrico
Key: last
Value: fermi
注意,即便遍历字典时,键—值对的返回顺序也与存储顺序不同。Python不关心键—值对的存储顺序,而只跟踪键和值之间的关联关系。
6.3.2 遍历字典中的所有键
在不需要使用字典中的值时,方法keys() 很有用。
favorite_languages = {
'jen': 'python',
'sarah': 'c',
'edward': 'ruby',
'phil': 'python',
}
for name in favorite_languages.keys():
print(name.title())
输出:
Sarah
Phil
Edward
Jen
favorite_languages = {
'jen': 'python',
'sarah': 'c',
'edward': 'ruby',
'phil': 'python',
}
friends = ['phil', 'sarah']
for name in favorite_languages.keys():
print(name.title())
if name in friends:
print(" Hi " + name.title() +
", I see your favorite language is " +
favorite_languages[name].title() + "!") #为访问喜欢的语言,使用字典名,并将变量name 的当前值作为键
输出:
Sarah
Hi Sarah, I see your favorite language is C!
Phil
Hi Phil, I see your favorite language is Python!
Edward
Jen
还可以使用keys() 确定某个人是否接受了调查。
favorite_languages = {
'jen': 'python',
'sarah': 'c',
'edward': 'ruby',
'phil': 'python',
}
if 'erin' not in favorite_languages.keys():
print("Erin, please take our poll!")
输出:
Erin, please take our poll!
6.3.3 按顺序遍历字典中的所有键
字典总是明确地记录键和值之间的关联关系,但获取字典的元素时,获取顺序是不可预测的。
要以特定的顺序返回元素,一种办法是在for 循环中对返回的键进行排序。为此,可使用函数sorted() 来获得按特定顺序排列的键列表的副本:
favorite_languages = {
'jen': 'python',
'sarah': 'c',
'edward': 'ruby',
'phil': 'python',
}
for name in sorted(favorite_languages.keys()): #使用sorted()对字典中的key进行排序
print(name.title() + ", thank you for taking the poll.")
输出:
Edward, thank you for taking the poll.
Jen, thank you for taking the poll.
Phil, thank you for taking the poll.
Sarah, thank you for taking the poll.
6.3.4 遍历字典中的所有值
如果你感兴趣的主要是字典包含的值,可使用方法values() ,它返回一个值列表,而不包含任何键。
favorite_languages = {
'jen': 'python',
'sarah': 'c',
'edward': 'ruby',
'phil': 'python',
}
print("The following languages have been mentioned:")
for language in favorite_languages.values():
print(language.title())
输出:
The following languages have been mentioned:
C
Python
Ruby
Python
这种做法提取字典中所有的值,而没有考虑是否重复。涉及的值很少时,这也许不是问题,但如果被调查者很多,最终的列表可能包含大量的重复项。为剔除重复项,可使用集合(set)。集合 集合 类似于列表,但每个元素都必须是独一无二的:
favorite_languages = {
'jen': 'python',
'sarah': 'c',
'edward': 'ruby',
'phil': 'python',
}
print("The following languages have been mentioned:")
for language in set(favorite_languages.values()): #方法set()去除重复值
print(language.title())
输出:
The following languages have been mentioned:
Python
C
Ruby
6.4 嵌套
有时候,需要将一系列字典存储在列表中,或将列表作为值存储在字典中,这称为嵌套。
6.4.1 字典列表
字典alien_0 包含一个外星人的各种信息,但无法存储第二个外星人的信息,更别说屏幕上全部外星人的信息了。如何管理成群结队的外星人呢?一种办法是创建一个外星人列 表,其中每个外星人都是一个字典,包含有关该外星人的各种信息。例如,下面的代码创建一个包含三个外星人的列表:
alien_0 = {'color': 'green', 'points': 5}
alien_1 = {'color': 'yellow', 'points': 10}
alien_2 = {'color': 'red', 'points': 15}
aliens = [alien_0, alien_1, alien_2] #通过创建一个列表来把三个外星人字典存到一起
for alien in aliens:
print(alien)
输出:
{‘points’: 5, ‘color’: ‘green’}
{‘points’: 10, ‘color’: ‘yellow’}
{‘points’: 15, ‘color’: ‘red’}
更符合现实的情形是,外星人不止三个,且每个外星人都是使用代码自动生成的。在下面的示例中,我们使用range() 生成了30个外星人:
#创建一个用于存储外星人的空列表
aliens = []
#创建30个绿色的外星人
for alien_number in range(30):
new_alien = {'color':'green','points':5,'speed':'slow'}
aliens.append(new_alien)
#显示前五个外星人
for alien in aliens[:5]:
print(alien)
print("____________________________________")
#显示创建了多少个外星人
print("Total number of aliens: " + str(len(aliens)))
输出:
{‘points’: 5, ‘speed’: ‘slow’, ‘color’: ‘green’}
{‘points’: 5, ‘speed’: ‘slow’, ‘color’: ‘green’}
{‘points’: 5, ‘speed’: ‘slow’, ‘color’: ‘green’}
{‘points’: 5, ‘speed’: ‘slow’, ‘color’: ‘green’}
{‘points’: 5, ‘speed’: ‘slow’, ‘color’: ‘green’}
Total number of aliens: 30
#创建一个用于存储外星人的空列表
aliens = []
#创建30个绿色的外星人
for alien_number in range(0,30):
new_alien = {'color':'green','points':5,'speed':'slow'}
aliens.append(new_alien)
#将前三个外星人修改为黄色的、速度为中等且值10个点
for alien in aliens[:3]:
if alien['color'] =='green':
alien['color'] = 'yellow'
alien['speed'] = 'medium'
alien['points'] = 10
# 显示前五个外星人
for alien in aliens[0:5]:
print(alien)
print("...")
输出:
{‘color’: ‘yellow’, ‘speed’: ‘medium’, ‘points’: 10}
{‘color’: ‘yellow’, ‘speed’: ‘medium’, ‘points’: 10}
{‘color’: ‘yellow’, ‘speed’: ‘medium’, ‘points’: 10}
{‘color’: ‘green’, ‘speed’: ‘slow’, ‘points’: 5}
{‘color’: ‘green’, ‘speed’: ‘slow’, ‘points’: 5}
…
6.4.2 在字典中存储列表
存储了比萨的两方面信息:外皮类型和配料列表。其中的配料列表是一个与键’toppings’ 相关联的值。要访问该列表,我们使用字典名和键’toppings’ ,就像访问字典中的其他值一样。这将返回一个配料列表,而不是单个值:
# 存储所点比萨的信息
pizza = {
'crust': 'thick',
'toppings': ['mushrooms', 'extra cheese'],
}
# 概述所点的比萨
print("You ordered a " +
pizza['crust'] +
"-crust pizza " +
"with the following toppings:")
for topping in pizza['toppings']:
print("\t" + topping)
输出:
You ordered a thick-crust pizza with the following toppings:
mushrooms
extra cheese
每当需要在字典中将一个键关联到多个值时,都可以在字典中嵌套一个列表。
6.4.3 在字典中存储字典
可在字典中嵌套字典,但这样做时,代码可能很快复杂起来。例如,如果有多个网站用户,每个都有独特的用户名,可在字典中将用户名作为键,然后将每位用户的信息存储在 一个字典中,并将该字典作为与用户名相关联的值。
在下面的程序中,对于每位用户,我们都存储了其三项信息:名、姓和居住地;为访问这些信息,我们遍历所有的用户名, 并访问与每个用户名相关联的信息字典:
users = {
'aeinstein': {
'first': 'albert',
'last': 'einstein',
'location': 'princeton',
},
'mcurie': {
'first': 'marie',
'last': 'curie',
'location': 'paris',
},
}
for username, user_info in users.items():
print("\nUsername: " + username)
full_name = user_info['first'] + "·" + user_info['last']
location = user_info['location']
print("\tFull name: " + full_name.title())
print("\tLocation: " + location.title())
输出:
Username: aeinstein
Full name: Albert·Einstein
Location: Princeton
Username: mcurie
Full name: Marie·Curie
Location: Paris
6.5 小结
遍历字典的时候不要忘记在字典名后加方法名items(),keys(),values()
第 7 章 用户输入和while 循环
7.1 函数input() 的工作原理 的工作原理
函数input() 让程序暂停运行,等待用户输入一些文本。获取用户输入后,Python将其存储在一个变量中,以方便你使用。
message = input("Tell me something, and I will repeat it back to you: ")
print(message)
输出:
Tell me something, and I will repeat it back to you: ASDFGHJKL
ASDFGHJKL
7.1.1 编写清晰的程序
每当你使用函数input() 时,都应指定清晰而易于明白的提示,准确地指出你希望用户提供什么样的信息——指出用户该输入任何信息的提示都行。
有时候,提示可能超过一行,例如,你可能需要指出获取特定输入的原因。在这种情况下,可将提示存储在一个变量中,再将该变量传递给函数input() 。这样,即便提示超过 一行,input() 语句也非常清晰。
#这个示例演示了一种创建多行字符串的方式。第1行将消息的前半部分存储在变量prompt 中;
#在第2行中,运算符+= 在存储在prompt 中的字符串末尾附加一个字符串。
prompt = "If you tell us who you are, we can personalize the messages you see."
prompt += "\nWhat is your first name? " #字符串拼接
name = input(prompt)
print("\nHello, " + name + "!")
输出:
If you tell us who you are, we can personalize the messages you see.
What is your first name? D
Hello, D!
7.1.2 使用int() 来获取数值输入
使用函数input() 时,Python将用户输入解读为字符串。
age = input("How old are you ? \n") #输入的age为字符串格式,所以下面在进行比较的时候需要加‘ ’
if age > '18':
print("\n你都" + age + "了,你个糟老头子坏得很!")
elif age <= '18':
print("\n小屁孩,你才" + age + "啊!")
输出:
How old are you ?
24
你都24了,你个糟老头子坏得很!
height = input("How tall are you, in inches? ")
height = int(height)
if height >= 36:
print("\nYou're tall enough to ride!")
else:
print("\nYou'll be able to ride when you're a little older.")
输出:
How tall are you, in inches? 111
You’re tall enough to ride!
#### 7.1.3 求模运算符
处理数值信息时,**求模运算符 (%)**是一个很有用的工具,它将两个数相除并返回余数。
number = input("Enter a number, and I'll tell you if it's even or odd: ")
number = int(number)
if number % 2 == 0:
print("\nThe number " + str(number) + " is even.")
else:
print("\nThe number " + str(number) + " is odd.")
输出:
Enter a number, and I’ll tell you if it’s even or odd: 0
The number 0 is even.
练习:
num = input("Please input a real number: \n")
num = int(num) #先把num从str换成int,方便下一步做运算
if num % 10 == 0:
print(str(num) + "是10的整数倍!") #再把num从int转换回str,方便输出
else:
print(str(num) + "不是10的整数倍!")
输出:
Please input a real number:
22
22不是10的整数倍!
7.2 while 循环简介
while 循环不断地运行,直到指定的条件不满足为止。
7.2.1 使用while 循环
current_number = 1
while current_number <= 5:
print(current_number)
current_number += 1
输出:
1
2
3
4
5
7.2.2 让用户选择何时退出
prompt = "\nTell me something, and I will repeat it back to you:"
prompt += "\nEnter 'quit' to end the program. "
message = ""
while message != 'quit':
message = input(prompt)
print(message)
##将最后两行代码互换可使最后的quit不输出
输出:
Tell me something, and I will repeat it back to you:
Enter ‘quit’ to end the program. QUit
QUit
Tell me something, and I will repeat it back to you:
Enter ‘quit’ to end the program. Quit
Quit
Tell me something, and I will repeat it back to you:
Enter ‘quit’ to end the program. quit
quit
7.2.3 使用标志
可定义一个变量,用于判断整个程序是否处于活动状态。这个变量被称为标志 标志 ,充当了程序的交通信号灯。你可让程序在标志 为True 时继续运行,并在任何事件导致标志的值为False 时让程序停止运行。这样,在while 语句中就只需检查一个条件——标志的当前值是否为True ,并将所有测试(是 否发生了应将标志设置为False 的事件)都放在其他地方,从而让程序变得更为整洁。
prompt = "\nTell me something, and I will repeat it back to you:"
prompt += "\nEnter 'quit' to end the program. "
active = True #active为标志
while active:
message = input(prompt)
if message == 'quit':
active = False
else:
print(message)
输出:
Tell me something, and I will repeat it back to you:
Enter ‘quit’ to end the program. jkjl
jkjl
Tell me something, and I will repeat it back to you:
Enter ‘quit’ to end the program. 分内的事看
分内的事看
Tell me something, and I will repeat it back to you:
Enter ‘quit’ to end the program. quit
7.2.4 使用break 退出循环
要立即退出while 循环,不再运行循环中余下的代码,也不管条件测试的结果如何,可使用break 语句。break 语句用于控制程序流程,可使用它来控制哪些代码行将执行, 哪些代码行不执行,从而让程序按你的要求执行你要执行的代码。
prompt = "\nPlease enter the name of a city you have visited:"
prompt += "\n(Enter 'quit' when you are finished.) "
while True:
city = input(prompt)
if city == 'quit':
break
else:
print("I'd love to go to " + city.title() + "!")
输出:
Please enter the name of a city you have visited:
(Enter ‘quit’ when you are finished.) jinan
I’d love to go to Jinan!
Please enter the name of a city you have visited:
(Enter ‘quit’ when you are finished.) taian
I’d love to go to Taian!
Please enter the name of a city you have visited:
(Enter ‘quit’ when you are finished.) quit
7.2.5 在循环中使用continue
要返回到循环开头,并根据条件测试结果决定是否继续执行循环,可使用continue 语句,它不像break 语句那样不再执行余下的代码并退出整个循环。
current_number = 0
while current_number < 10:
current_number += 1
if current_number % 2 == 0:
continue
print(current_number)
输出:
1
3
5
7
9
7.2.6 避免无限循环
要避免编写无限循环,务必对每个while 循环进行测试,确保它按预期那样结束。如果你希望程序在用户输入特定值时结束,可运行程序并输入这样的值;如果在这种情况下程 序没有结束,请检查程序处理这个值的方式,确认程序至少有一个这样的地方能让循环条件为False 或让break 语句得以执行。
注意 有些编辑器(如Sublime Text)内嵌了输出窗口,这可能导致难以结束无限循环,因此不得不关闭编辑器来结束无限循环。
练习:
有家电影院根据观众的年龄收取不同的票价:不到3岁的观众免费; 3~12岁的观众为10美元;超过12岁的观众为15美元。请编写一个循环,在其中询问用户的年龄,指出其票价。
程序1为(使用 break 语句在用户输入 ‘quit’ 时退出循环):
prompt = "\nPlease enter the your age:"
prompt += "\n(Enter 'quit' when you are finished.) "
while True :
age = input(prompt)
if age == 'quit':
break
else:
age=int(age)
if age<3:
print("free")
elif (age>=3 and age<=12):
print("The ticket price is 10 dollars.")
else:
print("The ticket price is 15 dollars.")
程序2为(使用变量 active 来控制循环结束的时机):
prompt = "\nPlease enter the your age:"
prompt += "\n(Enter 'quit' when you are finished.) "
active=True
while active :
age = input(prompt)
if age == 'quit':
active=False
else:
age=int(age)
if age<3:
print("free")
elif (age>=3 and age<=12):
print("The ticket price is 10 dollars.")
else:
print("The ticket price is 15 dollars.")
7.3 使用while循环来处理列表和字典
for 循环是一种遍历列表的有效方式,但在for 循环中不应修改列表,否则将导致Python难以跟踪其中的元素。要在遍历列表的同时对其进行修改,可使用while 循环。通过 将while 循环同列表和字典结合起来使用,可收集、存储并组织大量输入,供以后查看和显示。
7.3.1 在列表之间移动元素
假设有一个列表,其中包含新注册但还未验证的网站用户;验证这些用户后,如何将他们移到另一个已验证用户列表中呢?一种办法是使用一个while 循环,在验证用户的同时 将其从未验证用户列表中提取出来,再将其加入到另一个已验证用户列表中。
# 首先,创建一个待验证用户列表和一个用于存储已验证用户的空列表
unconfirmed_users = ['alice', 'brian', 'candace']
confirmed_users = []
# 验证每个用户,直到没有未验证用户为止,将每个经过验证的列表都移到已验证用户列表中
while unconfirmed_users:
current_user = unconfirmed_users.pop()
print("Verifying user: " + current_user.title())
confirmed_users.append(current_user)
# 显示所有已验证的用户
print("\nThe following users have been confirmed:")
for confirmed_user in confirmed_users:
print(confirmed_user.title())
输出:
Verifying user: Candace
Verifying user: Brian
Verifying user: Alice
The following users have been confirmed:
Candace
Brian
Alice
7.3.2 删除包含特定值的所有列表元素
pets = ['dog', 'cat', 'dog', 'goldfish', 'cat', 'rabbit', 'cat']
print(pets)
while 'cat' in pets:
pets.remove('cat')
print(pets)
输出:
[‘dog’, ‘cat’, ‘dog’, ‘goldfish’, ‘cat’, ‘rabbit’, ‘cat’]
[‘dog’, ‘dog’, ‘goldfish’, ‘rabbit’]
7.3.3 使用用户输入来填充字典
responses = {}
# 设置一个标志,指出调查是否继续
polling_active = True
while polling_active:
# 提示输入被调查者的名字和回答
name = input("\nWhat is your name? ")
response = input("Which mountain would you like to climb someday? ")
# 将答案存储在字典中
responses[name] = response #**字典名[key] = value 表示给字典中的key对应赋值value**
# 看看是否还有人要参与调查
repeat = input("Would you like to let another person respond? (yes/ no) ")
if repeat != 'yes':
polling_active = False
# 调查结束,显示结果
print("\n--- Poll Results ---")
for name, response in responses.items():
print(name + " would like to climb " + response + ".")
输出:
What is your name? lisa
Which mountain would you like to climb someday? tai
{‘lisa’: ‘tai’}
Would you like to let another person respond? (yes/ no) no
— Poll Results —
lisa would like to climb tai.
7.4 小结
开始变得复杂起来。
第 8 章 函数
函数是带名字的代码块,用于完成具体的工作。
8.1 定义函数
def greet_user():
print("Hello!")
greet_user()
输出:
Hello!
使用关键字def 来告诉Python你要定义一个函数。函数名为greet_user() ,它不需要任何信息就能完成其工作,因此括号是空的(即便如此,括号也必不可少)。最后,定义以冒号结尾。 紧跟在def greet_user(): 后面的所有缩进行构成了函数体。代码行print(“Hello!”) 是函数体内的唯一一行代码 。要使用这个函数,可调用它。要调用函数,可依次指定函数名以及用括号括起的必要信息,如处所示。由于这个函数不需要任何信息,因此调用它时只需输入greet_user() 即可。和预期的一样,它打印Hello!
8.1.1 向函数传递信息
def greet_user(username):
print("Hello," + username.title() + "!")
greet_user('Tom')
输出:
Hello,Tom!
8.1.2 实参和形参
在函数greet_user() 的定义中,变量username 是一个形参——函数完成其工作所需的一项信息。在代码greet_user(‘Tom’) 中,值’Tom’ 是一个实参。实参是调用函数时传递给函数的信息。我们调用函数时,将要让函数使用的信息放在括号内。在greet_user(‘Tom’) 中,将实参’Tom’ 传递给了函数greet_user() ,这个值被存储在形参username 中。
8.2 传递实参
鉴于函数定义中可能包含多个形参,因此函数调用中也可能包含多个实参。向函数传递实参的方式很多,可使用位置实参,这要求实参的顺序与形参的顺序相同;也可使用关键字实参 ,其中每个实参都由变量名和值组成;还可使用列表和字典。下面来依次介绍这些方式。
8.2.1 位置实参
你调用函数时,Python必须将函数调用中的每个实参都关联到函数定义中的一个形参。为此,最简单的关联方式是基于实参的顺序。这种关联方式被称为位置实参。
def describe_pet(animal_type, pet_name):
"""显示宠物的信息"""
print("\nI have a " + animal_type + ".")
print("My " + animal_type + "'s name is " + pet_name.title() + ".")
describe_pet('hamster', 'harry')
输出:
I have a hamster.
My hamster’s name is Harry.
1. 调用函数多次
2. 位置实参的顺序很重要
def describe_pet(animal_type, pet_name):
print("\nI have a " + animal_type + ".")
print("My " + animal_type + "'s name is " + pet_name.title() + ".")
describe_pet('harry', 'hamster')
输出:
I have a harry.
My harry’s name is Hamster.
8.2.2 关键字实参
关键字实参 关键字实参 是传递给函数的名称—值对。你直接在实参中将名称和值关联起来了,因此向函数传递实参时不会混淆(不会得到名为Hamster的harry这样的结果)。关键字实参让 你无需考虑函数调用中的实参顺序,还清楚地指出了函数调用中各个值的用途。
def describe_pet(animal_type, pet_name):
print("\nI have a " + animal_type + ".")
print("My " + animal_type + "'s name is " + pet_name.title() + ".")
describe_pet(pet_name='harry', animal_type='hamster')
输出:
I have a hamster.
My hamster’s name is Harry.
8.2.3 默认值
编写函数时,可给每个形参指定默认值。在调用函数中给形参提供了实参时,Python将使用指定的实参值;否则,将使用形参的默认值。因此,给形参指定默认值后,可在函数 调用中省略相应的实参。使用默认值可简化函数调用,还可清楚地指出函数的典型用法。
def describe_pet(pet_name, animal_type='dog'): #指定默认值animal_type='dog'
print("\nI have a " + animal_type + ".")
print("My " + animal_type + "'s name is " + pet_name.title() + ".")
describe_pet(pet_name='willie') #或者直接使用describe_pet('willie')
输出:
I have a dog.
My dog’s name is Willie.
注意 使用默认值时,在形参列表中必须先列出没有默认值的形参,再列出有默认值的实参。这让Python依然能够正确地解读位置实参。
8.2.4 等效的函数调用
8.2.5 避免实参错误
8.3 返回值
函数并非总是直接显示输出,相反,它可以处理一些数据,并返回一个或一组值。函数返回的值被称为返回值。在函数中,可使用return 语句将值返回到调用函数的代码行。
8.3.1 返回简单值
def get_formatted_name(first_name, last_name):
full_name = first_name + ' ' + last_name
return full_name.title()
musician = get_formatted_name('jimi', 'hendrix')
print(musician)
输出:
Jimi Hendrix
8.3.2 让实参变成可选的
def get_formatted_name(first_name, last_name, middle_name=''):
if middle_name:
full_name = first_name + ' ' + middle_name + ' ' + last_name
else:
full_name = first_name + ' ' + last_name
return full_name.title()
musician = get_formatted_name('jimi', 'hendrix')
print(musician)
musician = get_formatted_name('john', 'hooker', 'lee')
print(musician)
输出:
Jimi Hendrix
John Lee Hooker
8.3.3 返回字典
函数可返回任何类型的值,包括列表和字典等较复杂的数据结构。
def build_person(first_name, last_name):
person = {'first': first_name, 'last': last_name}
return person
musician = build_person('jimi', 'hendrix')
print(musician)
输出:
{‘last’: ‘hendrix’, ‘first’: ‘jimi’}
def build_person(first_name,last_name,age= ''):
person = {'first':first_name,'last':last_name}
if age:
person['age'] = age
return person
musician = build_person('jini','hendrix',age=27)
print(musician)
输出:
{‘last’: ‘hendrix’, ‘age’: 27, ‘first’: ‘jini’}
8.3.4 结合使用函数和while 循环
def get_formatted_name(first_name, last_name):
"""返回整洁的姓名"""
full_name = first_name + ' ' + last_name
return full_name.title()
while True:
print("\nPlease tell me your name:")
print("(enter 'q' at any time to quit)")
f_name = input("First name: ")
if f_name == 'q':
break
l_name = input("Last name: ")
if l_name == 'q':
break
formatted_name = get_formatted_name(f_name, l_name)
print("\nHello, " + formatted_name + "!")
输出:
Please tell me your name:
(enter ‘q’ at any time to quit)
First name: 董
Last name: 洋
Hello, 董 洋!
Please tell me your name:
(enter ‘q’ at any time to quit)
First name: 方
Last name: 方
Hello, 方 方!
Please tell me your name:
(enter ‘q’ at any time to quit)
First name: q
8.4 传递列表
def greet_users(names):
for name in names:
msg = "Hello, " + name.title() + "!"
print(msg)
usernames = ['hannah', 'ty', 'margot']
greet_users(usernames)
输出:
Hello, Hannah!
Hello, Ty!
Hello, Margot!
8.4.1 在函数中修改列表
在函数中对列表所做的任何修改都是永久性的。
# 首先创建一个列表,其中包含一些要打印的设计
unprinted_designs = ['iphone case', 'robot pendant', 'dodecahedron']
completed_models = []
# 模拟打印每个设计,直到没有未打印的设计为止 ,打印每个设计后,都将其移到列表completed_models中
while unprinted_designs:
current_design = unprinted_designs.pop()
#模拟根据设计制作3D打印模型的过程
print("Printing model: " + current_design)
completed_models.append(current_design)
# 显示打印好的所有模型
print("\nThe following models have been printed:")
for completed_model in completed_models:
print(completed_model)
输出:
Printing model: dodecahedron
Printing model: robot pendant
Printing model: iphone case
The following models have been printed:
dodecahedron
robot pendant
iphone case
8.4.2 禁止函数修改列表
要将列表的副本传递给函数,可以像下面这样做:
在调用函数make_great() 时,向它传递魔术师列表的副本。由于不想修改原始列表,请返回修改后的 列表,并将其存储到另一个列表中。分别使用这两个列表来调用show_magicians() ,确认一个列表包含的是原来的魔术师名字,而另一个列表包含的是添加了字 样“the Great”的魔术师名字。
function_name(list_name[:])
切片表示法[:] 创建列表的副本。
def show_magicians(name_list):
for name in name_list:
print(name)
def make_great(name_list,name_change):
while name_list:
current_name = name_list.pop();
current_name = "the Great " + current_name
name_change.append(current_name)
name_list = ['Alice','Tom','Bob','Hence']
name_change = []
make_great(name_list[:],name_change) #切片表示法,创建列表的副本,可以避免清空name_list
show_magicians(name_list)
print("————————")
show_magicians(name_change)
输出:
Alice
Tom
Bob
Hence
———————————————————
the Great Hence
the Great Bob
the Great Tom
the Great Alice
8.5 传递任意数量的实参
例如,来看一个制作比萨的函数,它需要接受很多配料,但你无法预先确定顾客要多少种配料。下面的函数只有一个形参*toppings ,但不管调用语句提供了多少实参,这个 形参都将它们统统收入囊中:
def make_pizza(*toppings):
print("\nMaking a pizza with the following toppings:")
for topping in toppings:
print("- " + topping)
make_pizza('pepperoni')
make_pizza('mushrooms', 'green peppers', 'extra cheese')
输出:
Making a pizza with the following toppings:
- pepperoni
Making a pizza with the following toppings:
- mushrooms
- green peppers
- extra cheese
8.5.1 结合使用位置实参和任意数量实参
如果要让函数接受不同类型的实参,必须在函数定义中将接纳任意数量实参的形参放在最后。Python先匹配位置实参和关键字实参,再将余下的实参都收集到最后一个形参中。
def make_pizza(size, *toppings):
"""概述要制作的比萨"""
print("\nMaking a " + str(size) +
"-inch pizza with the following toppings:")
for topping in toppings:
print("- " + topping)
make_pizza(16, 'pepperoni')
make_pizza(12, 'mushrooms', 'green peppers', 'extra cheese')
输出:
Making a 16-inch pizza with the following toppings:
- pepperoni
Making a 12-inch pizza with the following toppings:
- mushrooms
- green peppers
- extra cheese
8.5.2 使用任意数量的关键字实参
需要接受任意数量的实参,但预先不知道传递给函数的会是什么样的信息。在这种情况下,可将函数编写成能够接受任意数量的键—值对——调用语句提供了多少就接 受多少。一个这样的示例是创建用户简介:你知道你将收到有关用户的信息,但不确定会是什么样的信息。在下面的示例中,函数build_profile() 接受名和姓,同时还接受 任意数量的关键字实参:
def build_profile(first,last,**user_info):
profile = {}
profile['first_name'] = first
profile['last_name'] = last
for key,value in user_info.items():
profile[key] = value
return profile
user_profile = build_profile('albert','einstein',
location='priceton',
field='physics')
print(user_profile)
输出:
{‘first_name’: ‘albert’, ‘last_name’: ‘einstein’, ‘location’: ‘priceton’, ‘field’: ‘physics’}
函数build_profile() 的定义要求提供名和姓,同时允许用户根据需要提供任意数量的名称—值对。形参**user_info 中的两个星号让Python创建一个名为user_info 的 空字典,并将收到的所有名称—值对都封装到这个字典中。在这个函数中,可以像访问其他字典那样访问user_info 中的名称—值对。
8.6 将函数存储在模块中
函数的优点之一是,使用它们可将代码块与主程序分离。通过给函数指定描述性名称,可让主程序容易理解得多。你还可以更进一步,将函数存储在被称为 模块的独立文件中, 再将模块导入到主程序中。import 语句允许在当前运行的程序文件中使用模块中的代码。
8.6.1 导入整个模块
创建一个包含函数make_pizza() 的模块:
我们将文件pizza.py中 除函数make_pizza() 之外的其他代码都删除;
接下来,我们在pizza.py所在的目录中创建另一个名为making_pizzas.py的文件,这个文件导入刚创建的模块,再调用make_pizza() 两次:
8.6.2 导入特定的函数
from module_name import function_name
通过用逗号分隔函数名,可根据需要从模块中导入任意数量的函数
from module_name import function_0, function_1, function_2
8.6.3 使用as 给函数指定别名
指定别名的通用语法如下
from module_name import function_name as fn
下面给函数make_pizza() 指定了别名mp()
from pizza import make_pizza as mp
8.6.4 使用as给模块指定别名
给模块指定别名的通用语法如下
import module_name as mn
8.6.5 导入模块中的所有函数
使用星号(* )运算符可让Python导入模块中的所有函数
from module_name import *
8.7 函数编写指南
应给函数指定描述性名称,且只在其中使用小写字母和下划线。
每个函数都应包含简要地阐述其功能的注释,该注释应紧跟在函数定义后面,并采用文档字符串格式。
如果程序或模块包含多个函数,可使用两个空行将相邻的函数分开,这样将更容易知道前一个函数在什么地方结束,下一个函数从什么地方开始。
所有的import 语句都应放在文件开头,唯一例外的情形是,在文件开头使用了注释来描述整个程序。
8.8 小结
第 9 章 类
面向对象编程是最有效的软件编写方法之一。在面向对象编程中,你编写表示现实世界中的事物和情景的类,并基于这些类来创建对象。编写类时,你定义一大类对象都有的通用行为。基于类创建对象 时,每个对象都自动具备这种通用行为,然后可根据需要赋予每个对象独特的个性。使用面向对象编程可模拟现实情景,其逼真程度达到了令你惊讶的地步。
9.1 创建和使用类
使用类几乎可以模拟任何东西。下面来编写一个表示小狗的简单类Dog ——它表示的不是特定的小狗,而是任何小狗。对于大多数宠物狗,我们都知道些什么呢?它们都有名字 和年龄;我们还知道,大多数小狗还会蹲下和打滚。由于大多数小狗都具备上述两项信息(名字和年龄)和两种行为(蹲下和打滚),我们的Dog 类将包含它们。这个类让 Python知道如何创建表示小狗的对象。编写这个类后,我们将使用它来创建表示特定小狗的实例。
9.1.1 创建Dog 类
根据Dog 类创建的每个实例都将存储名字和年龄。我们赋予了每条小狗蹲下(sit() )和打滚(roll_over() )的能力:
class Dog():
# 一次模拟小狗的简单尝试
# 初始化属性name和age
def __init__(self, name, age):
self.name = name
self.age = age
def sit(self):
# 模拟小狗被命令时蹲下
print(self.name.title() + " is now sitting.")
def roll_over(self):
# 模拟小狗被命令时打滚
print(self.name.title() + " rolled over!")
在Python中,首字母大写的名称指的是类。这个类定义中的括号是空的,因为我们要从空白创建这个类。
1. 方法__init__()
类中的函数称为方法 方法 ;你前面学到的有关函数的一切都适用于方法,就目前而言,唯一重要的差别是调用方法的方式。方法__init__() 是一个特殊的方法,每当你根 据Dog 类创建新实例时,Python都会自动运行它。在这个方法的名称中,开头和末尾各有两个下划线,这是一种约定,旨在避免Python默认方法与普通方法发生名称冲突。
方法__init__() 定义包含三个形参:self 、name 和age 。在这个方法的定义中,形参self 必不可少,还必须位于其他形参的前面。为何必须在方法定义中包含形参self 呢?因为Python调用这个__init__() 方法来创建Dog实例时,将自动传入实参self 。每个与类相关联的方法调用都自动传递实参self ,它是一个指向实例本身的引用,让实例能够访问类中的属性和方法。我们创建Dog 实例时,Python将调用Dog类的方法__init__() 。我们将通过实参向Dog() 传递名字和年龄;self 会自动传递,因此我们不需要传递它。每当我们根据Dog 类创建实例时,都只需给最后两个形参(name 和age )提供值。
以self 为前缀的变量都可供类中的所有方法使用,我们还可以通过类的任何实例来访问这些变量。self.name = name 获取存储在形参name 中的值,并将其存储到变量name 中,然后该变量被关联到当前创建的实例。self.age = age 的作用与此类似。像这样可通过实例访问的变量称为属性。
Dog 类还定义了另外两个方法:sit() 和roll_over() 。由于这些方法不需要额外的信息,如名字或年龄,因此它们只有一个形参self 。我们后面将创建的实例能够访问这些方法,换句话说,它们都会蹲下和打滚。当前,sit() 和roll_over() 所做的有限,它们只是打印一条消息,指出小狗正蹲下或打滚。但可以扩展这些方法以模拟实际情况:如果这个类包含在一个计算机游戏中,这些方法将包含创建小狗蹲下和打滚动画效果的代码。如果这个类是用于控制机器狗的,这些方法将引导机器狗做出蹲下和打滚的动作。
9.1.2 根据类创建实例
可将类视为有关如何创建实例的说明。Dog 类是一系列说明,让Python知道如何创建表示特定小狗的实例。
下面来创建一个表示特定小狗的实例:
class Dog():
my_dog = Dog('willie', 6)
print("My dog's name is " + my_dog.name.title() + ".")
print("My dog is " + str(my_dog.age) + " years old.")
Python使用实参’willie’ 和6 调用Dog 类 中的方法__init__() 。方法__init__() 创建一个表示特定小狗的示例,并使用我们提供的值来设置属性name 和age 。方法__init__() 并未显式地包含return 语句, 但Python自动返回一个表示这条小狗的实例。我们将这个实例存储在变量my_dog 中。
通常可以认为首字母大写的名称(如Dog )指的是类,而 小写的名称(如my_dog )指的是根据类创建的实例。
1. 访问属性
句点表示法
my_dog.name
2. 调用方法
句点表示法来调用Dog 类中定义的任何方法:
class Dog():
my_dog = Dog('willie', 6)
my_dog.sit()
my_dog.roll_over()
3. 创建多个实例
可按需求根据类创建任意数量的实例。下面再创建一个名为your_dog 的实例:
class Dog():
my_dog = Dog('willie', 6)
your_dog = Dog('lucy', 3)
print("My dog's name is " + my_dog.name.title() + ".")
print("My dog is " + str(my_dog.age) + " years old.")
my_dog.sit()
print("\nYour dog's name is " + your_dog.name.title() + ".")
print("Your dog is " + str(your_dog.age) + " years old.")
your_dog.sit()
9.2 使用类和实例
类编写好后,可以根据类创建的实例。你需要执行的一个重要任务是修改实例的属性。你可以直接修改实例的属性,也可以编写方法以特定的方式进行修改。
9.2.1 Car 类
编写一个表示汽车的类,它存储了有关汽车的信息,还有一个汇总这些信息的方法:
class Car():
"""一次模拟汽车的简单尝试"""
def __init__(self, make, model, year):
"""初始化描述汽车的属性"""
self.make = make
self.model = model
self.year = year
def get_descriptive_name(self):
"""返回整洁的描述性信息"""
long_name = str(self.year) + ' ' + self.make + ' ' + self.model
return long_name.title()
my_new_car = Car('audi', 'a4', 2016)
print(my_new_car.get_descriptive_name())
输出:
2016 Audi A4
9.2.2 给属性指定默认值
类中的每个属性都必须有初始值,哪怕这个值是0或空字符串。在有些情况下,如设置默认值时,在方法__init__() 内指定这种初始值是可行的;如果你对某个属性这样做了,就无需包含为它提供初始值的形参。
class Car():
"""一次模拟汽车的简单尝试"""
def __init__(self, make, model, year):
"""初始化描述汽车的属性"""
self.make = make
self.model = model
self.year = year
self.odometer_reading = 0
def get_descriptive_name(self):
"""返回整洁的描述性信息"""
long_name = str(self.year) + ' ' + self.make + ' ' + self.model
return long_name.title()
def read_odometer(self):
"""打印一条指出汽车里程的消息"""
print("This car has " + str(self.odometer_reading) + " miles on it.")
my_new_car = Car('audi', 'a4', 2016)
print(my_new_car.get_descriptive_name())
my_new_car.read_odometer()
输出:
2016 Audi A4
This car has 0 miles on it.
9.2.3 修改属性的值
可以以三种不同的方式修改属性的值:直接通过实例进行修改;通过方法进行设置;通过方法进行递增(增加特定的值)。
1. 直接修改属性的值
要修改属性的值,最简单的方式是通过实例直接访问它。
my_new_car.odometer_reading = 23
my_new_car.read_odometer()
2. 通过方法修改属性的值
如果有替你更新属性的方法,将大有裨益。这样,你就无需直接访问属性,而可将值传递给一个方法,由它在内部进行更新。 下面的示例演示了一个名为update_odometer() 的方法:
class Car():
--snip-
def update_odometer(self, mileage):
"""将里程表读数设置为指定的值"""
self.odometer_reading = mileage
my_new_car = Car('audi', 'a4', 2016)
print(my_new_car.get_descriptive_name())
my_new_car.update_odometer(23)
my_new_car.read_odometer()
输出:
2016 Audi A4
This car has 23 miles on it.
可对方法update_odometer() 进行扩展,使其在修改里程表读数时做些额外的工作。下面来添加一些逻辑,禁止任何人将里程表读数往回调:
def update_odometer(self, mileage):
""" 将里程表读数设置为指定的值,禁止将里程表读数往回调 """
if mileage >= self.odometer_reading:
self.odometer_reading = mileage
else:
print("You can't roll back an odometer!")
3. 通过方法对属性的值进行递增
有时候需要将属性值递增特定的量,而不是将其设置为全新的值。假设我们购买了一辆二手车,且从购买到登记期间增加了100英里的里程,下面的方法让我们能够传递这个增 量,并相应地增加里程表读数:
class Car():
--snip -
def update_odometer(self, mileage):
--snip -
def increment_odometer(self, miles):
"""将里程表读数增加指定的量"""
self.odometer_reading += miles
my_used_car = Car('subaru', 'outback', 2013)
print(my_used_car.get_descriptive_name())
my_used_car.update_odometer(23500)
my_used_car.read_odometer()
my_used_car.increment_odometer(100)
my_used_car.read_odometer()
输出:
2013 Subaru Outback
This car has 23500 miles on it.
This car has 23600 miles on it.
新增的方法increment_odometer() 接受一个单位为英里的数字,并将其加入到self.odometer_reading 中。创建了一辆二手车 ——my_used_car 。调用方法update_odometer() 并传入23500 ,将这辆二手车的里程表读数设置为23 500。调用increment_odometer() 并传入100 ,以增加从购买到登记期间行驶的100英里。
注意 你可以使用类似于上面的方法来控制用户修改属性值(如里程表读数)的方式,但能够访问程序的人都可以通过直接访问属性来将里程表修改为任何值。要确 保安全,除了进行类似于前面的基本检查外,还需特别注意细节。
9.3 继承
如果你要编写的类是另一个现成类的特殊版本,可使用继承 。一个类继承另一个类时,它将自动获得另一个类的所有属性和方法;原有的类称为父类,而新类称为子类。子类继承了其父类的所有属性和方法,同时还可以定义自己的属性和方法。
9.3.1 子类的方法__init__()
创建子类的实例时,首先需要给父类的所有属性赋值。为此,子类的方法__init__() 需要父类施以援手。
下面来创建一个简单的ElectricCar 类版本,它具备Car 类的所有功能:
class Car():
"""一次模拟汽车的简单尝试"""
def __init__(self, make, model, year):
self.make = make
self.model = model
self.year = year
self.odometer_reading = 0
def get_descriptive_name(self):
long_name = str(self.year) + ' ' + self.make + ' ' + self.model
return long_name.title()
def read_odometer(self):
print("This car has " + str(self.odometer_reading) + " miles on it.")
def update_odometer(self, mileage):
if mileage >= self.odometer_reading:
self.odometer_reading = mileage
else:
print("You can't roll back an odometer!")
def increment_odometer(self, miles):
self.odometer_reading += miles
class ElectricCar(Car):
"""电动汽车的独特之处"""
def __init__(self, make, model, year):
"""初始化父类的属性"""
super().__init__(make, model, year)
my_tesla = ElectricCar('tesla', 'model s', 2016)
print(my_tesla.get_descriptive_name())
输出:
2016 Tesla Model S
创建子类时,父类必须包含在当前文件中,且位于子类前面。定义子类时,必须在括号内指定父类的 名称。方法__init__() 接受创建Car 实例所需的信息。
super() 是一个特殊函数,将父类和子类关联起来。让Python调用ElectricCar 的父类的方法__init__() ,让ElectricCar实例包含父类的所有属性。父类也称为超类(superclass),名称super因此而得名。
为测试继承是否能够正确地发挥作用,我们尝试创建一辆电动汽车,但提供的信息与创建普通汽车时相同。我们创建ElectricCar 类的一个实例,并将其存储在变量my_tesla 中。这行代码调用ElectricCar类中定义的方法__init__() ,后者让Python调用父类Car 中定义的方法__init__() 。我们提供了实参’tesla’ 、‘model s’ 和2016 。
9.3.2 Python 2.7中的继承
9.3.3 给子类定义属性和方法
让一个类继承另一个类后,可添加区分子类和父类所需的新属性和方法。
下面来添加一个电动汽车特有的属性(电瓶),以及一个描述该属性的方法。我们将存储电瓶容量,并编写一个打印电瓶描述的方法:
class ElectricCar(Car):
"""Represent aspects of a car, specific to electric vehicles."""
def __init__(self, make, model, year):
""" 电动汽车的独特之处 初始化父类的属性,再初始化电动汽车特有的属性 """
super().__init__(make, model, year)
self.battery_size = 70
def describe_battery(self):
"""打印一条描述电瓶容量的消息"""
print("This car has a " + str(self.battery_size) + "-kWh battery.")
my_tesla = ElectricCar('tesla', 'model s', 2016)
print(my_tesla.get_descriptive_name())
my_tesla.describe_battery()
输出:
2016 Tesla Model S
This car has a 70-kWh battery.
添加新属性self.battery_size 。根据ElectricCar 类创建的所有实例都将包含这个属性,但所有Car 实例都不包含它。
9.3.4重写父类的方法
对于父类的方法,只要它不符合子类模拟的实物的行为,都可对其进行重写。为此,可在子类中定义一个这样的方法,即它与要重写的父类方法同名。这样,Python将不会考虑这个父类方法,而只关注你在子类中定义的相应方法。
假设Car 类有一个名为fill_gas_tank() 的方法,它对全电动汽车来说毫无意义,因此你可能想重写它。下面演示了一种重写方式:
def fill_gas_tank():
"""电动汽车没有油箱"""
print("This car doesn't need a gas tank!")
如果对电动汽车调用方法fill_gas_tank() ,Python将忽略Car 类中的方法fill_gas_tank() ,转而运行上述代码。使用继承时,可让子类保留从父类那里继承而来的精华,并剔除不需要的糟粕。
9.3.5 将实例用作属性
使用代码模拟实物时,你可能会发现自己给类添加的细节越来越多:属性和方法清单以及文件都越来越长。在这种情况下,可能需要将类的一部分作为一个独立的类提取出来。 你可以将大型类拆分成多个协同工作的小类。
例如,不断给ElectricCar 类添加细节时,我们可能会发现其中包含很多专门针对汽车电瓶的属性和方法。在这种情况下,我们可将这些属性和方法提取出来,放到另一个名为Battery 的类中,并将一个Battery 实例用作ElectricCar 类的一个属性:
# class Car():
# """一次模拟汽车的简单尝试"""
# def __init__(self, make, model, year):
# self.make = make
# self.model = model
# self.year = year
# self.odometer_reading = 0
# def get_descriptive_name(self):
# long_name = str(self.year) + ' ' + self.make + ' ' + self.model
# return long_name.title()
# def read_odometer(self):
# print("This car has " + str(self.odometer_reading) + " miles on it.")
# def update_odometer(self, mileage):
# if mileage >= self.odometer_reading:
# self.odometer_reading = mileage
# else:
# print("You can't roll back an odometer!")
# def increment_odometer(self, miles):
# self.odometer_reading += miles
class Battery():
"""一次模拟电动汽车电瓶的简单尝试"""
def __init__(self, battery_size=70):
"""初始化电瓶的属性"""
self.battery_size = battery_size
def describe_battery(self):
"""打印一条描述电瓶容量的消息"""
print("This car has a " + str(self.battery_size) + "-kWh battery.")
class ElectricCar(Car):
"""电动汽车的独特之处"""
def __init__(self, make, model, year):
""" 初始化父类的属性,再初始化电动汽车特有的属性 """
super().__init__(make, model, year)
self.battery = Battery()
my_tesla = ElectricCar('tesla', 'model s', 2016)
print(my_tesla.get_descriptive_name())
my_tesla.battery.describe_battery()
定义了一个Battery类,它没有继承任何类。方法__init__() 除self 外,还有另一个形参battery_size 。这个形参是可选的:如果没有给它提供值,电瓶容量将被设置为70。方法describe_battery() 也移到了这个类中。
在ElectricCar 类中,添加了一个self.battery 的属性。这行代码让Python创建一个新的Battery 实例(由于没有指定尺寸,因此为默认值70 ),并将该实例存储在属性self.battery 中。每当方法__init__() 被调用时,都将执行该操作;因此现在每个ElectricCar 实例都包含一个自动创建的Battery 实例。
我们创建一辆电动汽车,并将其存储在变量my_tesla 中。要描述电瓶时,需要使用电动汽车的属性battery :
my_tesla.battery.describe_battery()
看似做了很多额外的工作,但现在我们想多详细地描述电瓶都可以,且不会导致ElectricCar 类混乱不堪。下面再给Battery 类添加一个方法,它根据电瓶容量报告汽车的续航里程:
class Car():
--snip-
class Battery():
--snip-
def get_range(self):
"""打印一条消息,指出电瓶的续航里程"""
if self.battery_size == 70:
range = 240
elif self.battery_size == 85:
range = 270
message = "This car can go approximately " + str(range)
message += " miles on a full charge."
print(message)
class ElectricCar(Car):
--snip-
my_tesla = ElectricCar('tesla', 'model s', 2016)
print(my_tesla.get_descriptive_name())
my_tesla.battery.describe_battery()
my_tesla.battery.get_range()
输出:
2016 Tesla Model S
This car has a 70-kWh battery.
This car can go approximately 240 miles on a full charge.
9.3.6 模拟实物
9.4 导入类
from car import Car
my_new_car = Car('audi', 'a4', 2016)
print(my_new_car.get_descriptive_name())
my_new_car.odometer_reading = 23
my_new_car.read_odometer()
输出:
2016 Audi A4
This car has 23 miles on it.
9.4.2 在一个模块中存储多个类
9.4.3 从一个模块中导入多个类
from car import Car, ElectricCar
9.4.4 导入整个模块
import car
9.4.5 导入模块中的所有类
from module_name import *
9.4.6 在一个模块中导入另一个模块
from car import Car
class Battery():
--snip-
class ElectricCar(Car):
--snip-
9.5 Python标准库
Python标准库是一组模块,安装的Python都包含它。可使用标准库中的任何函数和类,为此 只需在程序开头包含一条简单的import 语句。下面来看模块collections 中的一个类——OrderedDict 。字典让你能够将信息关联起来,但它们不记录你添加键—值对的顺序。要创建字典并记录其中的键—值对的添加顺序,可使用模块collections 中的OrderedDict 类。OrderedDict 实例的行为几乎与字典相同,区别只在于记录了键—值对的添加顺序。
9.6 类编码风格
类名应采用驼峰命名法 ,即将类名中的每个单词的首字母都大写,而不使用下划线。实例名和模块名都采用小写格式,并在单词之间加上下划线。
对于每个类,都应紧跟在类定义后面包含一个文档字符串。这种文档字符串简要地描述类的功能,并遵循编写函数的文档字符串时采用的格式约定。每个模块也都应包含一个文 档字符串,对其中的类可用于做什么进行描述。
可使用空行来组织代码,但不要滥用。在类中,可使用一个空行来分隔方法;而在模块中,可使用两个空行来分隔类。
需要同时导入标准库中的模块和你编写的模块时,先编写导入标准库模块的import 语句,再添加一个空行,然后编写导入你自己编写的模块的import 语句。在包含多 条import 语句的程序中,这种做法让人更容易明白程序使用的各个模块都来自何方。
9.7 小结
第 10 章 文件和异常
在本章中,你将学习处理文件,让程序能够快速地分析大量的数据;你将学习错误处理,避免程序在面对意外情形时崩溃;你将学习异常 ,它们是Python创建的特殊对象,用于管理程序运行时出现的错误;你还将学习模块json ,它让你能够保存用户数据,以免在程序停止运行后丢失。
学习处理文件和保存数据可让你的程序使用起来更容易:用户将能够选择输入什么样的数据,以及在什么时候输入;用户使用你的程序做一些工作后,可将程序关闭,以后再接着往下做。学习处理异常可帮助你应对文件不存在的情形,以及处理其他可能导致程序崩溃的问题。这让你的程序在面对错误的数据时更健壮,可提高程序的适用性、可用性和稳定性。
10.1 从文件中读取数据
文本文件可存储的数据量多得难以置信:天气数据、交通数据、社会经济数据、文学作品等。每当需要分析或修改存储在文件中的信息时,读取文件都很有用,对数据分析应用程序来说尤其如此。例如,你可以编写一个这样的程序:读取一个文本文件的内容,重新设置这些数据的格式并将其写入文件,让浏览器能够显示这些内容。
要使用文本文件中的信息,首先需要将信息读取到内存中。为此,你可以一次性读取文件的全部内容,也可以以每次一行的方式逐步读取。
10.1.1 读取整个文件
首先来手动创建一个文件,它包含精确到小数点后30位的圆周率值,且在小数点后每10位处都换行:
3.1415926535
8979323846
2643383279
下面的程序打开并读取这个文件,再将其内容显示到屏幕上:
with open('pi_digits.txt') as file_object:
contents = file_object.read()
print(contents)
输出:
3.1415926535
8979323846
2643383279
函数open()打开文件。函数open() 接受一个参数:要打开的文件的路径和名称。Python在当前执行的文件所在的目录中查找指定的文件。函数open() 返回一个表示文件的对象。
在这里,open(‘pi_digits.txt’) 返回一个表示文件pi_digits.txt 的对象;Python将这个对象存储在我们将 在后面使用的变量中。
关键字with 在不再需要访问文件后将其关闭。
使用方法read() 读取这个文件的全部内容,并将其作为一个长长的字符串存储在变量contents 中。这样,通过打印contents的值,就可将这个文本文件的全部内容显示出来。
相比于原始文件,该输出唯一不同的地方是末尾多了一个空行。因为read() 到达文件末尾时返回一个空字符串,而将这个空字符串显示出来时就是一个空行。要删除多出来的空行,可在print 语句中使用rstrip() :
with open('pi_digits.txt') as file_object:
contents = file_object.read()
print(contents.rstrip())
输出:
3.1415926535
8979323846
2643383279
10.1.2 文件路径
可使用相对文件路径来打开该文件夹中的文件。相对文件路径让Python到指定的位置去查找,而该位置是相对于当前运行的程序所在目录的。
with open('text_files\filename.txt') as file_object:
还可以将文件在计算机中的准确位置告诉Python,这样就不用关心当前运行的程序存储在什么地方了。这称为绝对文件路径。
file_path = 'C:\Users\ehmatthes\other_files\text_files\filename.txt' with open(file_path) as file_object:
10.1.3 逐行读取
filename = 'pi_digits.txt'
with open(filename) as file_object:
for line in file_object:
print(line)
输出:
3.1415926535
8979323846
2643383279
filename = 'pi_digits.txt'
with open(filename) as file_object:
for line in file_object:
print(line.rstrip())
输出:
3.1415926535
8979323846
2643383279
10.1.4 创建一个包含文件各行内容的列表
使用关键字with 时,open() 返回的文件对象只在with 代码块内可用。如果要在with 代码块外访问文件的内容,可在with代码块内将文件的各行存储在一个列表中,并在with代码块外使用该列表。
filename = 'pi_digits.txt'
with open(filename) as file_object:
lines = file_object.readlines()
for line in lines:
print(line.rstrip())
输出:
3.1415926535
8979323846
2643383279
方法readlines() 从文件中读取每一行,并将其存储在一个列表中;接下来,该列表被存储到变量lines 中;在with 代码块外,我们依然可以使用这个变量。
10.1.5 使用文件的内容
首先,我们将创建一个字符串,它包含文件中存储的所有数字,且没有任何空格:
filename = 'pi_digits.txt'
with open(filename) as file_object:
lines = file_object.readlines()
pi_string = ''
for line in lines:
pi_string += line.rstrip()
print(pi_string)
print(len(pi_string))
输出:
3.1415926535 8979323846 2643383279
36
在变量pi_string 存储的字符串中,包含原来位于每行左边的空格,为删除这些空格,可使用strip() 而不是rstrip() :
filename = 'pi_digits.txt'
with open(filename) as file_object:
lines = file_object.readlines()
pi_string = ''
for line in lines:
pi_string += line.strip()
print(pi_string)
print(len(pi_string))
输出:
3.141592653589793238462643383279
32
10.1.6 包含一百万位的大型文件
filename = 'pi_million_digits.txt'
with open(filename) as file_object:
lines = file_object.readlines()
pi_string = ''
for line in lines:
pi_string += line.strip()
print(pi_string[:52] + "...")
print(len(pi_string))
输出:
3.14159265358979323846264338327950288419716939937510…
1000002
10.1.7 圆周率值中包含你的生日吗
filename = 'pi_million_digits.txt'
with open(filename) as file_object:
lines = file_object.readlines()
pi_string = ''
for line in lines:
pi_string += line.rstrip()
birthday = input("Enter your birthday, in the form mmddyy: ")
if birthday in pi_string:
print("Your birthday appears in the first million digits of pi!")
else:
print("Your birthday does not appear in the first million digits of pi.")
输出:
Enter your birthdate, in the form mmddyy: 120372
Your birthday appears in the first million digits of pi!