2 变量和简单数据类型
2.2 变量
2.2.1 变量的命名和使用
牢记有关变量的规则
- 变量名只能包含字母、数字和下划线,变量名可以以字母或下划线开头,但不能以数字开头。错误示例:1_message。
- 变量名不能包含空格,但可使用下划线来分隔其中单词。错误示例:greeting message 。正确示例:
greeting_message
。 - 不要将Python关键字和函数名用作变量名
- 变量名应既简短又具描述性。例如:
name
比 n 好,student_name
比 s_n 好,name_length
比 length_of_persons_name 好。 - 慎用小写字母l和大写字母O,它们可能被人错看成数字1和0。
2.2.2 使用变量时避免明显错误
traceback是一条记录,指出了解释器尝试运行代码时,在什么地方陷入了困境。
要理解新的编程概念,最佳的方式是尝试在程序中使用它们。
2.3 字符串
2.3.1 使用方法修改字符串的大小写
代码:
name = "ada lovelace"
print name.title()
print name.upper()
print name.lower()
输出结果:
Ada Lovelace
ADA LOVELACE
ada lovelace
2.3.4 删除空白
str.rstrip([chars]) # 剔除字符串结尾的指定字符(默认为空白)
lstrip([chars]) # 剔除字符串开头的指定字符(默认为空白)
strip([chars]) # 同时剔除字符串开头和结尾的指定字符(默认为空白)
2.3.6 Python 2中的print语句
在Python 2中,无需将打印的内容放在括号内。
从技术上说,Python 3中的print
是一个函数,因此括号必不可少。
2.4 数字
2.4.4 Python 2中的整数
Python 2中,整数除法的结果只包含整数部分,小数部分被删除,注意不是四舍五入,而是直接删除小数部分。
Python 2中,要避免这种情况,务必确保至少有一个操作为浮点数,这样结果也将为浮点数。
2.5 注释
2.5.2 该编写什么样的注释
当前,大多数软件都是合作编写的,编写者可能是同一家公司的多名员工,也可能是众多致力于同一个开源项目的人员。训练有素的程序员都希望代码中包含注释,因此最好从现在开始就在程序中添加描述性注释。作为新手,最值得养成的习惯之一是,在代码中编写清晰、简洁的注释。
如果不确定是否要编写注释,就问问自己,找到合理的解决方案前,是否考虑了多个解决方案。如果答案是肯定的,就编写注释对的解决方案进行说明吧。相比回过头去再添加注释,删除多余的注释要容易得多。
2.6 Python之禅
在解释器中执行命令import this
就会显示Tim Peters的The Zen of 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!
3 列表简介
3.2.1 修改列表元素
motorcycles = [‘honda‘, ‘yamaha‘, ‘suzuki‘]
print (motorcycles)
motorcycles[0] = ‘ducati‘
print (motorcycles)
输出:
[‘honda‘, ‘yamaha‘, ‘suzuki‘]
[‘ducati‘, ‘yamaha‘, ‘suzuki‘]
3.2.2 在列表中添加元素
- 在列表末尾添加元素
motorcycles = [‘honda‘, ‘yamaha‘, ‘suzuki‘]
print(motorcycles)
motorcycles.append(‘ducati‘)
print(motorcycles)
输出:
[‘honda‘, ‘yamaha‘, ‘suzuki‘]
[‘honda‘, ‘yamaha‘, ‘suzuki‘, ‘ducati‘]
- 在列表中插入元素
使用方法insert()
可以在列表的任何位置添加新元素。需要制定新元素的索引和值。
motorcycles = [‘honda‘, ‘yamaha‘, ‘suzuki‘]
motorcycles.insert(0, ‘ducati‘)
print(motorcycles)
这种操作将列表既有的每个元素都右移一个位置:
[‘ducati‘, ‘honda‘, ‘yamaha‘, ‘suzuki‘]
3.2.3 从列表中删除元素
可以根据位置或值来删除列表中的元素。
- 使用
del
语句删除元素
motorcycles = [‘honda‘, ‘yamaha‘, ‘suzuki‘]
print(motorcycles)
del motorcycles[0]
print(motorcycles)
输出:
[‘honda‘, ‘yamaha‘, ‘suzuki‘]
[‘yamaha‘, ‘suzuki‘]
- 使用方法
pop()
删除元素
方法pop()
可删除列表末尾的元素,并能够接着使用它。
motorcycles = [‘honda‘, ‘yamaha‘, ‘suzuki‘]
print(motorcycles)
popped_motorcycle = motorcycles.pop()
print(motorcycles)
print(popped_motorcycle)
输出:
[‘honda‘, ‘yamaha‘, ‘suzuki‘]
[‘honda‘, ‘yamaha‘]
suzuki
- 弹出列表中任何位置处的元素
可以使用pop()
方法来删除列表中任何位置的元素,只需在括号中指定要删除的元素的索引即可。
motorcycles = [‘honda‘, ‘yamaha‘, ‘suzuki‘]
first_owned = motorcycles.pop(0)
print(‘The first motorcycle I owned was a ‘ + first_owned.title() + ‘.‘)
输出:
The first motorcycle I owned was a Honda.
- 根据值删除元素
可使用方法remove()
。
motorcycles = [‘honda‘, ‘yamaha‘, ‘suzuki‘, ‘ducati‘]
print(motorcycles)
motorcycles.remove(‘ducati‘)
print(motorcycles)
输出:
[‘honda‘, ‘yamaha‘, ‘suzuki‘, ‘ducati‘]
[‘honda‘, ‘yamaha‘, ‘suzuki‘]
使用remove()
从列表中删除元素时,也可接着使用它的值
motorcycles = [‘honda‘, ‘yamaha‘, ‘suzuki‘, ‘ducati‘]
too_expensive = ‘ducati‘
motorcycles.remove(too_expensive)
print(motorcycles)
值‘ducati‘已经从列表中删除,但它还存储在变量too_expensive
中
[‘honda‘, ‘yamaha‘, ‘suzuki‘, ‘ducati‘]
[‘honda‘, ‘yamaha‘, ‘suzuki‘]
A Ducati is too expensive for me.
方法remove()
只删除第一个指定的值。如果要删除的值可能在列表中出现多次,就需要使用循环来判断是否删除了所有这样的值。
3.3.1 使用方法sort()
对列表进行永久性排序
cars = [‘bmw‘, ‘audi‘, ‘toyota‘, ‘subaru‘]
cars.sort()
print(cars)
永久性排序:
[‘audi‘, ‘bmw‘, ‘subaru‘, ‘toyota‘]
可以按与字母顺序相反的顺序排列列表元素,为此,只需向sort()
方法传递参数reverse=True
。
cars = [‘bmw‘, ‘audi‘, ‘toyota‘, ‘subaru‘]
cars.sort(reverse=True)
print(cars)
同样是永久性修改列表元素顺序:
[‘toyota‘, ‘subaru‘, ‘bmw‘, ‘audi‘]
3.3.2 使用函数sorted()
对列表进行临时排序
cars = [‘bmw‘, ‘audi‘, ‘toyota‘, ‘subaru‘]
print("Here is the original list:")
print(cars)
print("\nHere is the sorted list:")
print(sorted(cars))
print("\nHere is the original list again:")
print(cars)
输出:
Here is the original list:
[‘bmw‘, ‘audi‘, ‘toyota‘, ‘subaru‘]
Here is the sorted list:
[‘audi‘, ‘bmw‘, ‘subaru‘, ‘toyota‘]
Here is the original list again:
[‘bmw‘, ‘audi‘, ‘toyota‘, ‘subaru‘]
如果要按与字母顺序相反的顺序显示列表,也可向函数sorted()
传递参数reverse=True
。
注意 在并非所有的值都是小写时,按字母顺序排列列表要复杂些。决定排列顺序时,有多种解读大写字母的方式,要指定准确的排列顺序,可能比我们这里所做的要复杂。
3.3.3 倒着打印列表
要反转列表元素的排列顺序,可使用方法reverse()
。
cars = [‘bmw‘, ‘audi‘, ‘toyota‘, ‘subaru‘]
print(cars)
cars.reverse()
print(cars)
注意,reverse()
不是指按与字母顺序相反的顺序排列列表元素,而只是反转列表元素的排列顺序:
[‘bmw‘, ‘audi‘, ‘toyota‘, ‘subaru‘]
[‘subaru‘, ‘toyota‘, ‘audi‘, ‘bmw‘]
方法reverse()
永久性地修改列表元素的排列顺序,但可随时恢复到原来的排列顺序,为此只需对列表再次调用reverse() 即可。
3.4 使用列表时避免索引错误
假设有一个包含三个元素的列表,却要求获取第四个元素:
motorcycles = [‘honda‘, ‘yamaha‘, ‘suzuki‘]
print(motorcycles[3])
这将导致索引错误 :
Traceback (most recent call last):
File "motorcycles.py", line 3, in <module>
print(motorcycles[3])
IndexError: list index out of range
索引错误意味着Python无法理解指定的索引。程序发生索引错误时,请尝试将指定的索引减1,然后再次运行程序,看看结果是否正确。
每当需要访问最后一个列表元素时,都可使用索引-1 。这在任何情况下都行之有效,即便最后一次访问列表后,其长度发生了变化。
4 操作列表
4.3 创建数值列表
4.3.1 使用函数range()
for value in range(1, 6):
print(value)
注意输出不包含第二个值:
1
2
3
4
5
函数range()
还可指定步长
语法:
range(start, stop[, step])
输入:
even_numbers = list(range(2,11,2))
print(even_numbers)
输出:
[2, 4, 6, 8, 10]
4.3.3 对数字列表执行简单的统计计算
min()
max()
sum()
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 = []
for value in range(1, 11):
squares.append(value**2)
print(squares)
4.4.3 复制列表
要复制列表,可创建一个包含整个列表的切片,方法是同时省略起始索引和终止索引([:]
)。
我们在不指定任何索引的情况下从列表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‘]
My friend‘s favorite foods are:
[‘pizza‘, ‘falafel‘, ‘carrot cake‘, ‘ice cream‘]
如果只是简单地将my_foods
赋给friend_foods
,就不能得到两个列表。
4.5 元组
列表非常适合用于存储在程序运行期间可能变化的数据集。
列表是可以修改的,这对处理网站的用户列表或游戏中的角色列表至关重要。然而,有时候需要创建一系列不可修改的元素,元组可以满足这种需求。
Python将不能修改的值称为不可变的 ,而不可变的列表被称为元组 。
4.5.1 定义元组
元组看起来犹如列表,但使用圆括号而不是方括号来标识。
dimensions = (200, 50)
dimensions[0] = 250
输出:
Traceback (most recent call last):
File "dimensions.py", line 3, in <module>
dimensions[0] = 250
TypeError: ‘tuple‘ object does not support item assignment
代码试图修改第一个元素的值,导致Python返回类型错误消息。由于试图修改元组的操作是被禁止的,因此Python指出不能给元组的元素赋值。
4.5.2 遍历元组中的所有值
可使用for循环来遍历元组中的所有值。
相比于列表,元组是更简单的数据结构。如果需要存储的一组值在程序的整个生命周期内都不变,可使用元组。
4.6 设置代码格式
4.6.1 格式设置指南
PEP 8是最古老的PEP(Python Enhancement Proposal,PEP)之一,它向Python程序员提供了代码格式设置指南。PEP 8的篇幅很长,但大都与复杂的编码结构相关。
如果一定要在让代码易于编写和易于阅读之间做出选择,Python程序员几乎总是会选择后者。
4.6.3 行长
很多Python程序员都建议每行不超过80字符。
PEP 8还建议注释的行长都不超过72字符,因为有些工具为大型项目自动生成文档时,会在每行注释开头添加格式化字符。
PEP 8中有关行长的指南并非不可逾越的红线,有些小组将最大行长设置为99字符。在学习期间,不用过多地考虑代码的行长,但别忘了,协作编写程序时,大家几乎都遵守PEP 8指南。在大多数编辑器中,都可设置一个视觉标志——通常是一条竖线,让你知道不能越过的界线在什么地方。
5 if语句
5.3.2 if-else 语句
else 语句指定了条件测试未通过时要执行的操作。
5.3.3 if-elif-else 结构
经常需要检查超过两个的情形,为此可使用Python提供的if-elif-else
结构。
Python只执行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.")
5.3.4 使用多个elif 代码块
可根据需要使用任意数量的elif
代码块:
age = 12
if age < 4:
price = 0
elif age < 18:
price = 5
elif age < 65:
price = 10
else:
price = 5
print("Your admission cost is $" + str(price) + ".")
5.3.5 省略else 代码块
Python并不要求if-elif 结构后面必须有else 代码块。在有些情况下,else 代码块很有用;而在其他一些情况下,使用一条elif 语句来处理特定的情形更清晰。
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) + ".")
else 是一条包罗万象的语句,只要不满足任何if 或elif 中的条件测试,其中的代码就会执行,这可能会引入无效甚至恶意的数据。如果知道最终要测试的条件,应考虑使用一个elif 代码块来代替else 代码块。这样就可以肯定,仅当满足相应的条件时,代码才会执行。
6 字典
可将任何Python对象用作字典中的值。
6.2.2 添加键-值对
字典是一种动态结构,可随时在其中添加键-值对。要添加键-值对,可依次指定字典名、用方括号括起的键和相关联的值。
alien_0 = {‘color‘: ‘green‘, ‘points‘: 5}
print(alien_0)
alien_0[‘x_position‘] = 0
alien_0[‘y_position‘] = 25
print(alien_0)
输出:
{‘color‘: ‘green‘, ‘points‘: 5}
{‘color‘: ‘green‘, ‘points‘: 5, ‘x_position‘: 0, ‘y_position‘: 25}
6.2.3 先创建一个空字典
使用字典来存储用户提供的数据或在编写能自动生成大量键-值对的代码时,通常都需要先定义一个空字典。
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.
6.2.5 删除键-值对
可使用del 语句将相应的键-值对彻底删除,使用del 语句时,必须指定字典名和要删除的键。
alien_0 = {‘color‘: ‘green‘, ‘points‘: 5}
print(alien_0)
del alien_0[‘points‘]
print(alien_0)
输出:
{‘color‘: ‘green‘, ‘points‘: 5}
{‘color‘: ‘green‘}
6.2.6 由类似对象组成的字典
确定需要使用多行来定义字典时,在输入左花括号后按回车键,再在下一行缩进四个空格,指定第一个键-值对,并在它后面加上一个逗号。此后再次按回车键时,文本编辑器将自动缩进后续键-值对,且缩进量与第一个键-值对相同。
定义好字典后,在最后一个键-值对的下一行添加一个右花括号,并缩进四个空格,使其与字典中的键对齐。另外一种不错的做法是在最后一个键-值对后面也加上逗号,为以后在下一行添加键-值对做好准备。
favorite_languages = {
‘jen‘: ‘python‘,
‘sarah‘: ‘c‘,
‘edward‘: ‘ruby‘,
‘phil‘: ‘python‘,
}
6.3 遍历字典
6.3.1 遍历所有的键-值对
user_0 = {
‘username‘: ‘efermi‘,
‘first‘: ‘enrico‘,
‘last‘: ‘fermi‘,
}
for key, value in user_0.items(): # for语句的第二部分包含字典名和方法items()
print("\nKey: " + key)
print("Value: " + value)
输出:
Key: last
Value: fermi
Key: first
Value: enrico
Key: username
Value: efermi
通过“+”连接符连接key
和value
:
favorite_languages = {
‘jen‘: ‘python‘,
‘sarah‘: ‘c‘,
‘edward‘: ‘ruby‘
‘phil‘: ‘python‘,
}
for name, language in favorite_languages.items():
print(name.title() + "‘s favorite language is " + language.title() + ".")
输出:
Jen‘s favorite language is Python.
Sarah‘s favorite language is C.
Phil‘s favorite language is Python.
Edward‘s favorite language is Ruby.
6.3.2 遍历字典中的所有键
在不需要使用字典中的值时,方法keys()
很有用。
favorite_languages = {
‘jen‘: ‘python‘,
‘sarah‘: ‘c‘,
‘edward‘: ‘ruby‘,
‘phil‘: ‘python‘,
}
for name in favorite_languages.keys():
print(name.title())
输出:
Jen
Sarah
Phil
Edward
遍历字典时,会默认遍历所有的键,因此,如果将上述代码中的for name in favorite_languages.keys():
替换为 for name in favorite_languages:
,输出将不变。
如果显式地使用方法keys()
可让代码更容易理解,你可以选择这样做,但如果你愿意,也可省略它。
favorite_languages = {
‘jen‘: ‘python‘,
‘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() + "!")
输出:
Edward
Jen
Phil
Hi Phil, I see your favorite language is Python!
7 用户输入和while循环
7.1 函数input()
函数input()
接受一个参数:即要向用户显示的提示 或说明,让用户知道该如何做。
7.1.1 编写清晰的程序
个性化打招呼:
name = input("Please enter your name: ")
print("Hello, " + name + "!")
7.1.2 使用int()
来获取数值输入
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? 71
You‘re tall enough to ride!
将数值输入用于计算和比较前,务必将其转换为数值表示。
7.1.4 在Python 2.7中获取输入
如果使用的是Python 2.7,应使用函数raw_input()
来提示用户输入。这个函数与Python 3中的input()
一样,也将输入解读为字符串。
Python 2.7也包含函数input()
,但它将用户输入解读为Python代码,并尝试运行它们。因此,最好的结果是出现错误,指出Python不明白输入的代码;而最糟的结果是,将运行原本无意运行的代码。
7.2.2 让用户选择何时退出
我们在其中定义了一个退出值,只要用户输入的不是这个值,程序就接着运行:
Tell me something, and I will repeat it back to you:
Enter ‘quit‘ to end the program. Hello everyone!
Hello everyone!
Tell me something, and I will repeat it back to you:
Enter ‘quit‘ to end the program. Hello again.
Hello again.
Tell me something, and I will repeat it back to you:
Enter ‘quit‘ to end the program. quit
代码:
prompt = "\nTell me something, and I will repeat it back to you:"
prompt += "\nEnter ‘quit‘ to end the program. "
message = ""
while message != ‘quit‘:
message = raw_input(prompt) # 注意raw_input()已包含print(prompt)步骤
#print(message)
if message == ‘quit‘:
print(message)
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
while active:
message = input(prompt)
if message == ‘quit‘:
active = False
else:
print(message)
7.2.4 使用break
退出循环
要立即退出while循环,不再运行循环中余下的代码,也不管条件测试的结果如何,可使用break语句。
注意: 在任何Python循环中都可使用break语句。例如,可使用break语句来退出遍历列表或字典的for循环。
7.2.5 在循环中使用 continue
要返回到循环开头,并根据条件测试结果决定是否继续执行循环,可使用continue语句,它不像break语句那样不再执行余下的代码并退出整个循环。
例如,来看一个从1数到10,但只打印其中偶数的循环:
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循环都必须有停止运行的途径,这样才不会没完没了地执行下去。
要避免编写无限循环,务必对每个while循环进行测试,确保它按预期那样结束。如果希望程序在用户输入特定值时结束,可运行程序并输入这样的值;如果在这种情况下程序没有结束,请检查程序处理这个值的方式,确认程序至少有一个这样的地方能让循环条件为False
或让break语句得以执行。
7.3 使用 while 循环来处理列表和字典
for循环是一种遍历列表的有效方式,但在for循环中不应修改列表,否则将导致Python难以跟踪其中的元素。
要在遍历列表的同时对其进行修改,可使用while循环。通过将while循环同列表和字典结合起来使用,可收集、存储并组织大量输入,供以后查看和显示。
7.3.2 删除包含特定值的所有列表元素
假设有一个宠物列表,其中包含多个值为‘cat‘的元素。要删除所有这些元素,可不断运行一个while循环,直到列表中不再包含值‘cat‘,如下所示:
pets = [‘dog‘, ‘cat‘, ‘dog‘, ‘goldfish‘, ‘cat‘, ‘rabbit‘, ‘cat‘]
print(pets)
while ‘cat‘ in pets:
pets.remove(‘cat‘) #list.remove(obj)移除列表中某个值的第一个匹配项
print(pets)
输出:
[‘dog‘, ‘cat‘, ‘dog‘, ‘goldfish‘, ‘cat‘, ‘rabbit‘, ‘cat‘]
[‘dog‘, ‘dog‘, ‘goldfish‘, ‘rabbit‘]
7.3.3 使用用户输入来填充字典
创建一个调查程序,其中的循环每次执行时都提示输入被调查者的名字和回答。我们将收集的数据存储在一个字典中,以便将回答同被调查者关联起来:
注意python2 中用raw_input()
,python3 中input()
responses = {}
# 设置一个标志,指出调查是否继续
polling_active = True
while polling_active:
# 提示输入被调查者的名字和回答
name = raw_input("\nWhat is your name? ")
response = raw_input("Which mountain would you like to climb someday? ")
# 将答卷存储在字典中
responses[name] = response
# 看看是否还有人要参与调查
repeat = raw_input("Would you like to let another person respond? (yes/ no) ")
if repeat == ‘no‘:
polling_active = False
# 调查结束,显示结果
print("\n--- Poll Results ---")
for name, response in responses.items():
print(name + " would like to climb " + response + ".")
输出:
What is your name? Eric
Which mountain would you like to climb someday? Denali
Would you like to let another person respond? (yes/ no) yes
What is your name? Lynn
Which mountain would you like to climb someday? Devil‘s Thumb
Would you like to let another person respond? (yes/ no) no
--- Poll Results ---
Lynn would like to climb Devil‘s Thumb.
Eric would like to climb Denali.
8 函数
8.5.2 使用任意数量的关键字实参
有时候,需要接受任意数量的实参,但预先不知道传递给函数的会是什么样的信息。在这种情况下,可将函数编写成能够接受任意数量的键-值对——调用语句提供了多少就接受多少。
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=‘princeton‘,
field=‘physics‘)
print(user_profile)
输出:
{‘field‘: ‘physics‘, ‘first_name‘: ‘albert‘, ‘last_name‘: ‘einstein‘, ‘location‘: ‘princeton‘}
形参**user_info
中的两个星号让Python创建一个名为user_info
的空字典,并将收到的所有名称-值对都封装到这个字典中。在这个函数中,可以像访问其他字典那样访问user_info
中的名称—值对。
在这里,返回的字典包含用户的名和姓,还有求学的地方和所学专业。编写函数时,可以以各种方式混合使用位置实参、关键字实参和任意数量的实参。
8.6 将函数存储在模块中
将函数存储在被称为模块的独立文件中,再将模块导入到主程序中,import
语句允许在当前运行的程序文件中使用模块中的代码。
通过将函数存储在独立的文件中,可隐藏程序代码的细节,将重点放在程序的高层逻辑上。
这还能让你在众多不同的程序中重用函数。将函数存储在独立文件中后,可与其他程序员共享这些文件而不是整个程序。
知道如何导入函数还能让你使用其他程序员编写的函数库。
8.6.1 导入整个模块
import module_name
如果使用import
语句导入了名为module_name.py的整个模块,就可使用下面的语法来使用其中任何一个函数:
module_name.function_name()
8.6.2 导入特定的函数
from module_name import function_name
通过用逗号分隔函数名,可根据需要从模块中导入任意数量的函数:
from module_name import function_0, function_1, function_2
若使用这种语法,调用函数时就无需使用句点。由于在import
语句中显式地导入了函数function_name()
,因此调用它时只需指定其名称。
8.6.3 使用 as 给函数指定别名
如果要导入的函数的名称可能与程序中现有的名称冲突,或者函数的名称太长,可指定简短而独一无二的别名——函数的另一个名称,类似于外号。要给函数指定这种特殊外号,需要在导入它时这样做。
下面给函数make_pizza()
指定了别名mp()
。这是在import
语句中使用make_pizza as mp
实现的,关键字as
将函数重命名为你提供的别名:
from pizza import make_pizza as mp
mp(16, ‘pepperoni‘)
mp(12, ‘mushrooms‘, ‘green peppers‘, ‘extra cheese‘)
上面的import语句将函数make_pizza()
重命名为mp()
;在这个程序中,每当需要调用make_pizza()
时,都可简写成mp()
,而Python将运行make_pizza()
中的代码,这可避免与这个程序可能包含的函数make_pizza()
混淆。
指定别名的通用语法如下:
from module_name import function_name as fn
8.6.4 使用 as 给模块指定别名
给模块指定别名的通用语法:
import module_name as mn
8.6.5 导入模块中的所有函数
使用星号(*)运算符可让Python导入模块中的所有函数。
由于导入了每个函数,可通过名称来调用每个函数,而无需使用句点表示法。
然而,使用并非自己编写的大型模块时,最好不要采用这种导入方法:如果模块中有函数的名称与你的项目中使用的名称相同,可能导致意想不到的结果:Python可能遇到多个名称相同的函数或变量,进而覆盖函数,而不是分别导入所有的函数。
最佳的做法是,要么只导入你需要使用的函数,要么导入整个模块并使用句点表示法。这能让代码更清晰,更容易阅读和理解。
之所以介绍这种导入方法,只是想让你在阅读别人编写的代码时,如果遇到类似于下面的import语句,能够理解它们:
from module_name import *
# 不推荐使用该种导入方法!!!
8.7 函数编写指南
- 应给函数指定描述性名称,且只在其中使用小写字母和下划线。
- 每个函数都应包含简要地阐述其功能的注释,该注释应紧跟在函数定义后面,并采用文档字符串格式。
- 如果形参很多,导致函数定义的长度超过了79字符,可在函数定义中输入左括号后按回车键,并在下一行按两次Tab键,从而将形参列表和只缩进一层的函数体区分开来。
- 如果程序或模块包含多个函数,可使用两个空行将相邻的函数分开,这样将更容易知道前一个函数在什么地方结束,下一个函数从什么地方开始。
- 所有的
import
语句都应放在文件开头,唯一例外的情形是,在文件开头使用了注释来描述整个程序。
9 类
9.3 继承
9.3.1 子类的方法 __init__()
"""electric_car.py"""
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.modes
return long_name.title()
def read_odometer(self):
print("This car has " + str(self.odometer_reading) + " miles on in.")
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())
创建子类时,父类必须包含在当前文件中,且位于子类前面。
定义子类时,必须在括号内指定父类的名称。ElectricCar中方法__init__()
接受创建Car实例所需的信息。
super()
是一个特殊函数,帮助Python将父类和子类关联起来。这行代码让Python调用ElectricCar的父类的方法__init__()
,让ElectricCar实例包含父类的所有属性。父类也称为超类(superclass),名称super因此而得名。
9.3.2 Python 2.7中的继承
在Python 2.7中,继承语法稍有不同,ElectricCar类的定义类似于下面这样:
class Car(object):
def __init__(self, make, model, year):
--snip--
class ElectricCar(Car):
def __init__(self, make, model, year):
super(ElectricCar, self).__init__(make, model, year)
--snip--
函数super()
需要两个实参:子类名和对象self。为帮助Python将父类和子类关联起来,这些实参必不可少。
另外,在Python 2.7中使用继承时,务必在定义父类时在括号内指定object
。
9.3.4 重写父类的方法
对于父类的方法,只要它不符合子类模拟的实物的行为,都可对其进行重写。为此,可在子类中定义一个这样的方法,即它与要重写的父类方法同名。这样,Python将不会考虑这个父类方法,而只关注你在子类中定义的相应方法。
假设Car类有一个名为fill_gas_tank()
的方法,它对全电动汽车来说毫无意义,因此你可能想重写它。
def ElectricCar(Car):
--snip-
def fill_gas_tank():
"""电动汽车没有油箱"""
print("This car doesn‘t need a gas tank!")
现在,如果有人对电动汽车调用方法fill_gas_tank()
,Python将忽略Car类中的方法fill_gas_tank()
,转而运行上述代码。使用继承时,可让子类保留从父类那里继承而来的精华,并剔除不需要的糟粕。