Python 笔记
第二章 变量和简单数据类型
变量是可以赋予值的标签,也就是说变量指向特定的值。
2.1 变量的命名
-
由字母、数字、下划线组成,不能由数字开头,区分大小写
- (目前,应用小写的变量名,虽然使用大写字母不会导致错误)
-
不要使用Python关键字和函数名
-
变量名最好简短、具有描述性(慎用小写字母l和大写字母O,容易看错)
2.2 字符串
---由单引号/双引号括起
- 因此,可在字符串中灵活使用""和''
- 空白:任何非打印字符,如空格、制表符、换行符。
-
在字符串中添加制表符:\t
-
添加换行符:\n
-
字符串“\n\t”表示换到下一行并在下一行开头添加制表符
-
2.2.1 修改字符串大小写
- 每个单词首字母大写:title()
- 字符串全大写:upper()
- 字符串全小写:lower()
name="ada lovelace"
print(name.title()) # Ada Lovelace
print(name.upper()) # ADA LOVELACE
print(name.lower()) # ada lovelace
⚠️ print()会自动换行。
2.2.2 在字符串中使用变量
-
Python3.6引入
f字符串
:要在字符串中插入变量时,在前引号前添加字母f,将要插入的变量用花括号包起。则当Python显示该字符串时,会将变量替换为其值。first_name='ada' last_name='lovelace' full_name=f'{first_name} {last_name}' print(full_name) # ada lovelace
-
Python3.5及更早的版本,要使用
format()方法
:在字符串中插入变量时,使用花括号代替,format()圆括号内列出具体变量。Python会按顺序将花括号替换为圆括号中变量的值。full_name='{} {}'.format(first_name,last_name)
-
将数值转换为字符串时在其中添加逗号标识的千位分隔符。
score_str = "{:,}".format(score)
2.2.3 合并(拼接)字符串
---使用加号(+)合并字符串[拼接]
2.2.4 删除空白
(空白符:空格、换行符、制表符等)
- 删除字符串首端空白:lstrip()
- 删除字符串尾端空白:rstrip()
- 删除字符串首尾两端空白:strip()
favorite_language=' python '
print(favorite_language.lstrip()) # 'python '
print(favorite_language.rstrip()) #' python'
print(favorite_language.strip()) #'python'
2.2.5 字符替换 —— replace()
将字符串中的特定单词string1替换为另一个单词string2 —— replace(string1, string2, [count])
- 可添加形参count,不写默认都替换;否则表示最多替换前count个
- 函数返回一个新的copy
message = "I really like dogs. My dog names Jack."
message = message.replace('dog', 'cat')
print(message) # I really like cats. My cat names Jack.
2.2.6 字符串分割 —— split()
str.split(str="", num=string.count(str))
# str -- 分隔符,默认为所有的空字符,包括空格、换行(\n)、制表符(\t)等。
# num -- 分割次数。默认为 -1, 即分隔所有。
# 函数返回字符串列表
2.2.7 字符串计数 —— count()
str.count(sub, start=0,end=len(string))
# sub -- 搜索的子字符串
# start -- 字符串开始搜索的索引。默认为0.
# end -- 字符串中结束搜索的索引。默认为字符串的最后一个位置。
a = 'adddaddd'
print(a.count('a', 0, 4)) # 1
print(a.count('a', 0, 5)) # 2
2.3 数字
-
可使用括号修改运算次序
-
整除运算符
//
,它将两个数相除并丢弃余数。 -
两个乘号表示乘方,2表示平方,**3表示三次方
3 ** 3 # 27
-
浮点数结果包含的小数位数可能是不确定的
-
python2中整数除法结果为整数. Eg: 2/3=1,若要避免,则要保证至少有一个操作数为浮点数,Eg: 2.0/3=1.5;
python3中整数除法结果为浮点数 -
将非字符串值表示为字符串:str(变量)
age = 23 message = "Happy "+str(age)+"rd Birthday!" print(message) #Happy 23rd Birthday!
-
Python3.6中,书写很大的数时,可使用下划线将其中的数字分组,从而更清晰易读。Python存储这种数时,会忽略其中的下划线。
universe_age = 14_000_000_000
2.4 同时给多个变量赋值
在一行代码中可同时给多个变量赋值,需用逗号隔开。
x, y, z = 0, 0, 0
2.5 常量
Python中没有内置的常量类型,但程序员会使用全大写来将某个变量视为常量,其值应始终不变。
MAX_COUNT = 5000
2.6 注释
---使用#标识,#后边的内容被python解释器忽略
第三章 列表简介
---用方括号([])来表示列表,并用逗号分隔其中的元素
如果通过print函数将列表打印出来,Python将打印列表的内部表示,包括方括号。
bicycle=['trek','cannondale','redline']
print(bicycle) # ['trek','cannondale','redline']
3.1 访问列表元素
---通过下标访问列表元素,索引从0开始
将索引指定为-1,返回最后一个列表元素(负数索引返回离列表末尾相应距离的元素)
bicycle=['trek','cannondale','redline']
print(bicycle[0].title()) # Trek
print(bicycle[-1]) # redline
3.2 在列表中添加元素
- 在列表末尾添加元素:append()
- 在列表中插入元素:insert() 需指定元素的索引和值。
motorcycles=[]
motorcycles.append('honda')
motorcycles.append("yamaha")
print(motorcycles) # ['honda', 'yamaha']
motorcycles.insert(0,'uducate')
print(motorcycles) # ['uducate', 'honda', 'yamaha']
3.3 从列表中删除元素
-
使用del语句
- 要知道删除的元素的索引
motorcycles = ['honda', 'yamaha', 'suzuki'] print(motorcycles) # ['honda', 'yamaha', 'suzuki'] del motorcycles[1] print(motorcycles) # ['honda', 'suzuki']
-
使用pop()方法
- pop()可得到删除元素的值并在列表中删除它
- 可指定索引,默认删除末尾元素
motorcycles = ['honda', 'yamaha', 'suzuki'] popped_m1 = motorcycles.pop() print(popped_m1) # suzuki print(motorcycles) #['honda', 'yamaha'] popped_m2 = motorcycles.pop(0) print(popped_m2) # honda print(motorcycles) #['yamaha']
-
根据值删除元素---remove(value)
- 若value在列表中出现多次,只删除第一个
motorcycles = ['honda', 'yamaha', 'suzuki', 'yamaha'] motorcycles.remove('yamaha') print(motorcycles) # ['honda', 'suzuki', 'yamaha']
- 若要删除列表中所有的value,则需使用循环
3.4 组织列表
- 对列表进行永久性排序:sort()---默认按字母顺序排列,sort(reverse=True)按字母反向排列
- 对列表进行临时排序:sorted(list)---默认按字母顺序排列,也可传递参数reverse=True,返回值为列表
- 永久性反转列表:reverse()---若要恢复原来顺序,再次reverse即可
- 确定列表长度:len(list)
cars = ['bmw', 'audi', 'toyota', 'subaru']
cars.sort()
print(cars) # ['audi', 'bmw', 'subaru', 'toyota']
cars = ['bmw', 'audi', 'toyota', 'subaru']
cars.sort(reverse=True)
print(cars) # ['toyota', 'subaru', 'bmw', 'audi']
cars = ['bmw', 'audi', 'toyota', 'subaru']
print(sorted(cars)) # ['audi', 'bmw', 'subaru', 'toyota']
print(cars) # ['bmw', 'audi', 'toyota', 'subaru']
cars = ['bmw', 'audi', 'toyota', 'subaru']
cars.reverse()
print(cars) # ['subaru', 'toyota', 'audi', 'bmw']
print(len(cars)) # 4
第四章 操作列表
4.1 遍历列表——for循环
-
⚠️ for首句后有冒号,用于告诉Python下一行是循环的第一行。
-
Python根据缩进来判断代码行与前一个代码行的关系。
for循环后每个缩进的代码行都是循环的一部分。
cats = ['alice', 'david', 'carolina', 'jack']
for cat in cats:
print(cat.title()+" is a good cat!")
print("I love "+cat.title()+".\n")
print("That's all")
# 输出:
# Alice is a good cat!
# I love Alice.
#
# David is a good cat!
# I love David.
#
# Carolina is a good cat!
# I love Carolina.
#
# Jack is a good cat!
# I love Jack.
#
# That's all
4.2 创建数值列表
-
使用函数生成一系列数 range()——range(begin, end, step)
- 从begin开始,每次增加一个步长step,到end结束(包括begin,不包括end,默认begin=0,step=1)。
- 使用range()时,若输出不符合预期,可尝试将指定的值加1或减1。
for value in range(1,6): print(value) # 输出: # 1 # 2 # 3 # 4 # 5
-
使用range()创建数字列表
-
使用函数list()可将range()的结果直接转换为数字列表
even_number = list(range(2, 10+1, 2)) print(even_number) #[2, 4, 6, 8, 10]
-
使用range()创建任何需要的数字列表
squares = [] for value in range(1, 11): squares.append(value**2) print(squares) # [1, 4, 9, 16, 25, 36, 49, 64, 81, 100] # 与以下方式等价 【列表推导式,总是放在中括号中】 x_value = list(range(1, 11)) squares = [x**2 for x in x_value]
python中,**2表示平方,**3表示立方,**0.5表示平方根
-
-
对数字列表执行简单的统计计算
- 最大值---max(list)
- 最小值---min(list)
- 总和---sum(list)
-
列表解析
列表解析
:将for循环和创建新元素的代码合并成一行,并自动附加新元素。squares = [value**2 for value in range(1, 11)] print(squares) # [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
⚠️ 这里for语句没有冒号!
个人理解,for语句的冒号是为了指明循环体,但是此处无需循环体
4.3 使用列表的部分元素(切片)
4.3.1 切片
-
创建切片,可指定起始元素和终止元素的索引。(同样包含起始元素,不包含终止元素)
- ⚠️ 是索引,和range中的值不同。
- 若未指定起始索引,默认从列表开头开始;若未指定终止元素索引,默认终止于列表末尾。
- 切片的方括号内可指定第三个值(步长),告诉Python在指定范围内每隔多少元素提取一个。
players = ['charles', 'martina', 'michael', 'florence', 'eli'] print(players[1:4]) # ['martina', 'michael', 'florence']
-
遍历切片:在for循环中使用切片
players = ['charles', 'martina', 'michael', 'florence', 'eli'] print("我们队中的前三个队员:") for player in players[:3]: print(player.title()) # 输出: # 我们队中的前三个队员: # Charles # Martina # Michael
4.3.2 复制列表
---创建一个包含整个列表的切片,即同时省略起始索引和终止索引([ : ])。
my_foods = ['pizza', 'falafel', 'carrot cake']
friend_foods = my_foods[:]
print("我喜欢的食物是:"+str(my_foods)) # 我喜欢的食物是:['pizza', 'falafel', 'carrot cake']
print("我朋友喜欢的食物是:"+str(friend_foods)) # 我朋友喜欢的食物是:['pizza', 'falafel', 'carrot cake']
⚠️ 若写成:friend_foods = my_foods 则不能得到两个列表。(这种语法实际上是将新变量friend_foods关联到包含在my_foods中的列表,因此这两个变量都指向同一个列表)
使用for循环遍历列表时,Python 要求列表的长度在整个循环中需保持不变。所以不能在for循环遍历的列表中删除元素,若要删除,可遍历列表的副本。
for food in my_foods[:]:
4.4 元组
-
列表适合用于存储在程序运行期间可变的数据集(列表是可以修改的),使用方括号标识。
-
不可变的列表称为
元组
,使用圆括号标识。 -
元组的遍历于访问与列表操作相同。
-
试图修改元组的操作是非法的,但允许给元组重新赋值。
Rectangle = (200, 50) Rectangle[0] = 250 # 报错 Rectangle = (400, 100) # 合法 for value in Rectangle: print(value)
-
⚠️ 严格来说,元组由逗号标识,圆括号只是让其看起来更清晰。故若定义只包含一个元素的元组,也必须在此元素后面加逗号。
my_t = (3,)
创建只包含一个元素的元组通常无意义,但自动生成的元组可能只有一个元素_(:з」∠)_
个人理解:
range()生成一系列数,调用 list()可将之转换为列表,列表是被方括号括起的一系列元素。
切片是列表的一部分,它指向列表,所以可通过切片改变列表中元素的值。
(复制列表则需要将切片赋值给一个新的变量)
元组是不可变的列表,用圆括号标识。
第五章 if语句
5.1 示例
cars = ['audi', 'bmw', 'subaru', 'toyota']
for car in cars:
if car == 'bmw': #注意要有冒号
print(car.upper())
else:
print(car.title())
5.2 条件测试
-
检查是否相等:==
- 考虑大小写,若想忽略大小写时,可将变量转换为小写再比较 Eg:car.lower() == 'audi'
-
检查是否不等:!=
-
同时满足多个条件:and
-
满足多个条件中的一个:or
-
判断列表中是否存在特定值:in
-
判断列表中是否不存在特定值:not in
banned_users = ['andrew', 'carolina', 'david'] user = 'marie' if user not in banned_users: print(user.title() + ", you can post a response if you wish.")
-
布尔表达式:True、False(注意要大写!)
game_active = True can_edit = False
5.3 if语句多种结构
-
if语句
-
if-else语句
-
if-elif-else结构
age = 12 if age < 4: price = 0 elif age < 18: price = 5 elif age < 65: price = 10 else: price = 5 print("你的票价是 $" + str(price) + "。")
-
使用多个elif代码块
age = 12 if age < 4: price = 0 elif age < 18: price = 5 elif age < 65: price = 10 elif age >= 65: price = 5 print("你的票价是 $" + str(price) + "。")
5.4 使用if语句处理列表
-
判定列表是否为空——if list:
requested_toppings = [] if requested_toppings: for requested_topping in requested_toppings: print("Adding " + requested_topping + ".") print("Finished making your pizza!") else: print("Are you sure you want a plain pizza?") # 输出:Are you sure you want a plain pizza?
if list:
非空时执行 if 中的内容。if not list:
为空时执行 if 中的内容。 -
判断字符串是否为空——if string:
(若一字符串string=“”,则 if string返回False)
-
使用多个列表
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("Finished making your pizza!") # 输出: # Adding mushrooms. # Sorry, we don't have french fries. # Adding extra cheese. # Finished making your pizza!
第六章 字典
- 字典是一系列
键-值对
,可通过键访问与之相关联的值。 - Python中,字典是一种动态结构,用放在花括号{}中的一系列
键-值对
表示,键与值之间用冒号分隔,键-值对之间用逗号分隔。
6.1 使用字典
-
通过键获取对应的值
alien = {'color': 'green', 'points': 5} print(alien['color']) # green
-
通过get()访问值
若通过键获取对应值时,该键不存在,则会报错。此时应考虑使用get()方法。
get(key, [value])——第一个参数指定键;第二个参数为指定键不存在时要返回的值,默认为None。
alien = {'color': 'green', 'points': 5} print(alien.get('speed','No speed value assigned.')) # No speed value assigned.
-
修改键对应的值
alien = {'color': 'green', 'points': 5} alien['color']='yellow'
-
添加键-值对
alien = {'color': 'green', 'points': 5} alien['x_position'] = 0 alien['y_position'] = 25 print(alien) #{'color': 'green', 'points': 5, 'x_position': 0, 'y_position': 25}
-
删除键-值对——使用del语句
alien = {'color': 'green', 'points': 5} del alien['points'] print(alien) # {'color': 'green'}
-
创建空字典
alien={} # PS:用花括号创建的也可能是空集合set
6.2 遍历字典
-
得到字典的所有键-值对:items()——返回一个键-值对列表
-
遍历字典:for k, v in dictionary.items():
(items方法返回一个一个键-值对列表,Python遍历列表中的每一个键-值对,并将键、值存储在声明的两个变量k、v中。)
# 遍历字典 for k, v in dictionary.items(): user_0 = { 'username': 'efermi', 'first': 'enrico', 'last': 'fermi', } for key, value in user_0.items(): print("Key: " + key) print("Value: " + value) # 输出: # Key: username # Value: efermi # Key: first # Value: enrico # Key: last # Value: fermi
-
-
得到字典的所有键:keys()——返回一个键列表
-
遍历字典所有键:for k in dictionary.keys(): 或 for k in dictionary:
(因为遍历字典时,默认遍历所有的键,故keys()可省略)
-
keys()方法并非只用于遍历:因为它返回的是个包含所有键列表,则可使用 not in等判断元素是否在列表中。
favorite_languages = { 'jen': 'python', 'sarah': 'c', 'edward': 'ruby', 'phil': 'python', } for name in favorite_languages.keys(): print(name.title()) if 'erin' not in favorite_languages.keys(): print("Erin, please take our poll!") # 输出: # Jen # Sarah # Edward # Phil # Erin, please take our poll!
-
-
得到字典的所有值:values()——返回一个值列表
- 遍历字典的所有值:for v in dictionary.values():
favorite_languages = { 'jen': 'python', 'sarah': 'c', 'edward': 'ruby', 'phil': 'python', } for language in favorite_languages.values(): print(language.title()) # 输出: # Python # C # Ruby # Python
-
遍历字典时,键-值对的返回顺序与存储顺序不同(Python不关心键-值对的存储顺序,只跟踪键和值之间的关联关系)
若以特定顺序返回元素,可在for循环中对返回的值进行排序——sorted()
favorite_languages = { 'jen': 'python', 'sarah': 'c', 'edward': 'ruby', 'phil': 'python', } for language in sorted(favorite_languages.values()): print(language.title()) # 输出: # C # Python # Python # Ruby
⚠️ Python3.7中,字典中元素的排列顺序与定义时相同。
-
使用集合(set)可剔除列表中的重复项——set()
集合中每个原色都是独一无二的。
favorite_languages = { 'jen': 'python', 'sarah': 'c', 'edward': 'ruby', 'phil': 'python', } for language in set(favorite_languages.values()): print(language.title()) # 输出 # C # Python # Ruby
PS:可使用一对花括号直接创建集合,其中元素以逗号分隔。
不同于列表和字典,集合不会以特定的顺序存储元素。
languages={'python','java','c'} print(languages) # {'python','java','c'}
6.3 嵌套
将一系列字典存储在列表中,或将列表作为值存储在字典中。
(可以在列表中嵌套字典,在字典中嵌套列表,在字典中嵌套字典)
6.3.1 字典列表(在列表中嵌套字典)
Eg:字典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)
# 输出:
# {'color': 'green', 'points': 5}
# {'color': 'yellow', 'points': 10}
# {'color': 'red', 'points': 15}
PS:更符合现实的情形是,外星人不止三个,且每个外星人都是使用代码自动生成的:
# 创建一个用于存储外星人的空列表
aliens = []
# 创建30个绿色的外星人
for alien_number in range(30):
new_alien = {'color': 'green', 'points': 5, 'speed': 'slow'}
aliens.append(new_alien)
for alien in aliens[0: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', 'points': 10, 'speed': 'medium'}
# color': 'yellow', 'points': 10, 'speed': 'medium'}
# {'color': 'yellow', 'points': 10, 'speed': 'medium'}
# {'color': 'green', 'points': 5, 'speed': 'slow'}
# {'color': 'green', 'points': 5, 'speed': 'slow'}
# ...
6.3.2 在字典中存储列表
当需要在字典中将一个键关联到多个值时,可在字典中嵌套一个列表。
Eg:每个人喜欢的语言存储在字典中,若一个人喜欢多种语言,则可用一个列表来存储语言信息。
favorite_languages = {
'jen': ['python', 'ruby'],
'sarah': ['c'],
'edward': ['ruby', 'go'],
'phil': ['python', 'haskell'],
}
for name, languages in favorite_languages.items():
if len(languages) == 1:
print(name.title()+"'s favorite language is:\n\t"+languages[0].title())
else:
print(name.title()+"'s favorite languages are:")
for language in languages:
print('\t'+language.title())
# 输出
# Jen's favorite languages are:
# Python
# Ruby
# Sarah's favorite language is:
# C
# Edward's favorite languages are:
# Ruby
# Go
# Phil's favorite languages are:
# Python
# Haskell
6.3.3 在字典中存储字典
Eg:某网站有多个用户,每个用户有不同的用户名,可在字典中将用户名作为键,然后将每位用户的信息存储在一个字典中,并将该字典作为与用户名相关联的值。(这种情况,也可通过在用户列表中嵌套字典实现)
⚠️ 字典中的字典结构最好相同(虽然Python没有此要求,但这使得嵌套的字典处理起来更容易,否则for循环内部代码将更复杂)
users = {
'aeinstein': {
'first': 'albert',
'last': 'einstein',
'location': 'princeton',
},
'mcurie': {
'first': 'marie',
'last': 'curie',
'location': 'paris',
},
}
for username, user_info in users.items():
print("Username: " + 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
小结:
range()生成一系列数;列表用方括号标识,元组以圆括号标识,字典与集合以花括号标识(元素间都通过逗号分隔)。range()通过调用 list()可将之转换为列表。
切片是列表的一部分,它指向列表,所以可通过切片改变列表中元素的值。
(复制列表则需要将切片赋值给一个新的变量)元组是不可变的列表,其本质用逗号标识,故若定义只有一个元素的元组,也需在元素后加逗号。
字典中的元素是一系列键值对,键和值之间用冒号。
列表通过调用 set() 可转换为集合。集合中的元素都唯一,但不会以特定的顺序存储元素(不同于列表和字典)。
6.4 对字典列表进行排序
根据字典中的某个键值对字典列表进行排序—— 使用模块operator
中的函数itemgetter(键值对应的键)
from operator import itemgetter
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]
aliens = sorted(aliens, key=itemgetter('points'), reverse=True)
# 或 aliens.sort(key=itemgetter('points'), reverse=True)
for alien in aliens:
print(alien)
# 输出:
# {'color': 'red', 'points': 15}
# {'color': 'yellow', 'points': 10}
# {'color': 'green', 'points': 5}
第七章 用户输入和while循环
7.1 用户输入
-
获取用户输入:input()
- 函数input()可无参数,也可有一个参数,用于展示需要向用户显示的提示或说明。
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: Hello everyone! # Hello everyone!
PS:提示可能超过一行,这时为了代码清晰,可将提示存储在一个变量中,再将该变量传递给input()
-
获取数值输入:int(变量)、float(变量)
- 使用input()获取的输入都是字符串类型,可使用int()将之转换为整数,使用float()转换为浮点数
age = input("How old are you? ") age = int(age)
PS:字符串转数值:str(变量)
数值转字符串:int(变量)、float(变量)
-
求模运算:% 返回余数
-
在Python 2.7中使用raw_input()提示用户输入
(Python 2.7也有函数input(),但它将用户输入解读为Python代码,并尝试运行它们)
7.2 while循环
-
善用标志变量
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)
-
使用break语句退出循环
prompt = "\nTell me something, and I will repeat it back to you:" prompt += "\nEnter 'quit' to end the program. " while True: message = input(prompt) if message == 'quit': break else: print(message)
-
使用continue语句跳过当前循环
7.3 使用while循环处理列表和字典
-
while list: ——列表为空时结束循环
# 首先,创建一个待验证用户列表 # 和一个用于存储已验证用户的空列表 unconfirmed_users = ['alice', 'brian', 'candace'] confirmed_users = [] # 验证每个用户,直到没有未验证用户为止 # 将每个经过验证的列表都移到已验证用户列表中 while unconfirmed_users: current_user = unconfirmed_users.pop() print("正在验证用户: " + current_user.title()) confirmed_users.append(current_user) # 显示所有已验证的用户 print("\n下列用户已验证:") for confirmed_user in confirmed_users: print(confirmed_user.title()) # 输出 # 正在验证用户: Candace # 正在验证用户: Brian # 正在验证用户: Alice # # 下列用户已验证: # Candace # Brian # Alice
-
删除列表中中的所有特定值
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', 'cat', 'rabbit', 'cat']
-
使用用户输入填充字典
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 # 看看是否还有人要参与调查 repeat = 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 + ".")
第八章 函数
函数是带名称的代码块,用于完成具体工作,可将代码与主程序分离,让主程序更易理解。
每个函数最好只负责一项具体的工作,不要“身兼多职”。
8.1 定义函数
-
函数定义格式:
def 函数名([形参列表]): ["""文档字符串"""] 函数方法体
函数调用格式:
函数名([实参列表])
-
文档字符串
:用三引号
括起,描述函数是做什么的,Python使用它们来生成有关程序中函数的文档。 -
形参:函数完成其工作所需的一项信息。
-
实参:调用函数时传递给函数的信息。
def greet_user(username): """显示简单的问候语""" print('Hello,' + username.title() + '!') greet_user('jesse') #输出:Hello,Jesse!
8.2 传递实参
向函数传递参数的方式:位置实参、关键字实参、列表、字典。
8.2.1 位置实参
要求实参和形参的顺序相同。
def describe_pet(animal_type, pet_name):
"""显示宠物的信息"""
print("我有一只" + animal_type + "。")
print("我的" + animal_type + "的名字是" + pet_name.title() + "。")
describe_pet('金毛', '旺财')
# 输出:
# 我有一只金毛。
# 我的金毛的名字是旺财。
8.2.2 关键字实参
关键字参数传递给函数的是名称-值对
,所以无需考虑函数调用中的实参顺序,这种方式更清楚地指出了函数调用中各个值的用途。
def describe_pet(animal_type, pet_name):
"""显示宠物的信息"""
print("我有一只" + animal_type + "。")
print("我的" + animal_type + "的名字是" + pet_name.title() + "。")
describe_pet(animal_type='金毛', pet_name='旺财')
# 输出:
# 我有一只金毛。
# 我的金毛的名字是旺财。
8.2.3 设置形参默认值
调用函数时若给形参提供了实参,则使用指定的实参值;否则,使用形参的默认值。(使用默认值让实参变成可选的。)
⚠️ 形参的默认值必须从右往左写。
def describe_pet(pet_name, animal_type='狗'):
"""显示宠物的信息"""
print("我有一只" + animal_type + "。")
print("我的" + animal_type + "的名字是" + pet_name.title() + "。")
describe_pet('旺财')
# 输出:
# 我有一只狗。
# 我的狗的名字是旺财。
8.2.4 传递列表
-
将列表传递给函数后,在函数中对此列表做出的任何修改都是永久性的。
def print_models(unprinted_designs, completed_models): """ 模拟打印每个设计,直到没有未打印的设计为止 打印每个设计后,都将其移到列表completed_models中 """ while unprinted_designs: current_design = unprinted_designs.pop() # 模拟根据设计制作3D打印模型的过程 print("Printing model: " + current_design) completed_models.append(current_design) def show_completed_models(completed_models): """显示打印好的所有模型""" print("The following models have been printed:") for completed_model in completed_models: print(completed_model) unprinted_designs = ['iphone case', 'robot pendant', 'dodecahedron'] completed_models = [] print_models(unprinted_designs, completed_models) show_completed_models(completed_models) # 输出: # Printing model: dodecahedron # Printing model: robot pendant # Printing model: iphone case # The following models have been printed: # dodecahedron # robot pendant # iphone case
-
若希望向函数传递列表的副本而不是原件,可使用
切片表示法
创建列表的副本。调用函数格式:
函数名(列表名[:])
Eg:1中若不想清空未打印的设计列表,可如下调用print_models()
print_models(unprinted_designs[:], completed_models)
PS⚠️:虽然向函数传递列表的副本可保留原始列表中的内容,但尽量不要这么做,因为让函数使用现成列表可避免花时间和内存创建副本,从而提高效率,在处理大型列表时尤其如此。
8.3 返回值
- 函数可以返回任何类型的值,包括是列表或字典。
- return None 表示返回空,做if判断时,为False。
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('jimi', 'hendrix', age=27)
print(musician)
# 输出:
# {'first': 'jimi', 'last': 'hendrix', 'age': 27}
8.4 传递任意数量的实参
-
传递任意数量的实参——使用
*形参名
(星号让Python创建一个名为形参名的
空元组
,并将收到的所有值都封装进这个元组中)def make_pizza(*toppings): """概述要制作的比萨""" print("使用以下材料做一个披萨:") for topping in toppings: print("- " + topping) make_pizza('pepperoni') make_pizza('mushrooms', 'green peppers', 'extra cheese') # 输出: # 使用以下材料做一个披萨: # - pepperoni # 使用以下材料做一个披萨: # - mushrooms # - green peppers # - extra cheese
-
结合使用位置实参和任意参数实参——注意必须将接纳任意数量实参的形参放在最后
(Python先匹配位置参数和关键字实参,再将余下的实参都收集到最后一个形参中)
def make_pizza(size, *toppings): """概述要制作的比萨""" print("用以下材料做一个" + str(size) + "寸的披萨") for topping in toppings: print("- " + topping) make_pizza(16, 'pepperoni') make_pizza(12, 'mushrooms', 'green peppers', 'extra cheese') # 输出: # 使用以下材料做一个16寸披萨: # - pepperoni # 使用以下材料做一个12寸披萨: # - mushrooms # - green peppers # - extra cheese
-
使用任意数量的关键字实参——使用
**形参名
(两个星号让Python创建一个名为形参名的
空字典
,并将收到的所有名称-值对
都封装进此字典中)有时,需接受任意数量的实参,但是预先不知道传递给函数的会是什么信息,此情况下,可将函数编写成能接受任意数量的
键-值对
——调用语句提供了多少就接受多少。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) # 输出: # {'first_name': 'albert', 'last_name': 'einstein', 'location': 'princeton', 'field': 'physics'}
8.5 将函数存储在模块中
-
函数的优点是将代码块与主程序分离,通过给函数指定描述性名称,让主程序更易理解。
进一步地,可将函数存储在被称为
模块
的独立文件中,再将模块导入到主程序中。(模块名全小写,单词之间加下划线) -
import语句——允许在当前运行的程序文件中使用模块中的代码。
8.5.1 导入整个模块
-
导入模块格式——
import
module_name(python运行代码行import module_name时,会将其中的所有函数都复制到此程序中)
-
使用此模块中的任意一函数格式—— module_name.function_name()
(句点表示法——需指定模块名和函数名,中间用点号连接)
8.5.2 导入模块中的特定函数
-
导入模块中特定函数格式——
from
module_nameimport
function_name- 通过逗号分隔函数名,可导入模块中任意数量的函数——
from
module_nameimport
function_0, function_1, function_2
- 通过逗号分隔函数名,可导入模块中任意数量的函数——
-
使用此模块中的任意一函数格式—— function_name()
(无需指定模块名,因为在import语句中已显式导入此函数,故调用时只需指定函数名)
8.5.3 导入模块中的所有函数
-
导入模块格式——
from
module_nameimport
*-
星号运算符让Python导入模块中的所有函数
-
⚠️ 使用非自己编写的大型模块时,最好不要用此导入方式,因为模块和本项目可能存在多个名称相同的函数或变量,进而覆盖函数。
(故最佳的做法是——导入所需函数,或导入整个模块并使用句点表示法)
-
-
使用此模块中的任意一函数格式—— function_name()
8.5.4 使用as指定别名
- 给模块指定别名——
import
module_nameas
mn - 给函数指定别名——
from
module_nameimport
function_nameas
fn- 若导入的函数名称与程序中现有的名称冲突,或函数名称太长,可指定函数别名。
8.6 函数编写指南
-
函数/模块应指定描述性名称,且只使用小写字母和下划线。(大写字母不会有错误,但是最好别用)
-
函数都应有简要阐述其功能的注释,此注释应采用文档字符串格式(三引号括起)并紧跟在函数定义后。
-
指定形参默认值时,等号两边不要有空格。
def function_name(parameter_0, parameter_1='default name')
-
同理,调用函数时若使用关键字实参,等号两边也不要有空格。
function_name(value_0, parameter_1='value_1')
-
若形参很多,导致函数定义时长度超过79字符,可在函数定义中输入左括号后按回车键,并在下一行按两个Tab键,将形参列表与函数体区分开,便于代码阅读。
def function_name( parameter_0, parameter_1, parameter_2, parameter_3, parameter_4, parameter_5): function body...
-
若程序或模块包含多个函数,可使用 两个空行 将相邻函数分开。
-
所有import语句应放在文件开头,除非文件开头使用注释来描述整个程序。
第九章 类
9.1 创建和使用类
-
类名中每个单词首字母都需大写,不使用下划线 ——
驼峰命名法
类包含
方法
和属性
(类中的函数称为方法) -
__init__()
是个特殊的方法(相当于java中的构造函数),此方法必须有形参self
,且self必须位于其他形参前面。-
self
是一个指向实例本身的引用,让实例能访问类中的属性和方法。(类中编写的方法若要操作属性,一定要加形参self,使用self.property的方式得到属性值。)
-
__init__()
方法中 以self
为前缀的变量是属性,可供类中所有方法使用,可通过实例访问(属性也可以是某个类)。 -
__init__()
方法中可为属性指定默认值,但若指定了默认值,__init__()方法就不能给通过形参重新给它赋值,需要重新写一个set方法更换它的值。(所以还不如指定形参的默认值)
class Dog(): """一次模拟小狗的简单尝试""" def __init__(self, name, age): # 开头末尾各有两个下划线,旨在避免Python默认方法与普通方法发生名称冲突 """初始化属性name和age""" self.name = name self.age = age self.gender = '男' # 设置性别默认值 def sit(self): """模拟小狗被命令时蹲下""" print(self.name.title() + " is now sitting.") def roll_over(self): """模拟小狗被命令时打滚""" print(self.name.title() + " rolled over!")
PS:在Python2.7中创建类时,需要在括号内包含单词object:
class ClassName(object): --略--
-
-
实例名都小写,单词之间添加下划线。
- 访问实例的属性、调用方法,都使用
句点表示法
。
my_dog = Dog('willie', 6) print("我的狗狗名字是" + my_dog.name.title() + "。") print("它" + str(my_dog.age) + "岁了,是个" + my_dog.gender + "孩。") my_dog.sit() # 输出: # 我的狗狗名字是Willie。 # 它6岁了,是个男孩。 # Willie is now sitting.
- 访问实例的属性、调用方法,都使用
-
修改属性的值:
- 直接通过实例访问属性进行修改;
- 通过方法进行设置。
9.2 继承
子类
继承其父类
的所有属性和方法,同时还可以定义自己的属性和方法。(父类也称超类
)
- 创建子类时,父类必须包含在当前文件中,且位于子类的前面。
- 定义子类时,必须在括号内指定父类的名称。
- 子类的方法
__init__()
- 创建子类实例时,需先给父类的所有属性赋值。因此要写
super().__init__(父类属性参数列表)
super()
是个特殊函数,通过它可调用父类的方法。
- 创建子类实例时,需先给父类的所有属性赋值。因此要写
- 子类继承父类后,可添加新的属性和方法,也可重写父类方法。
- 重写父类方法,要求与父类方法同名
class 子类名(父类名):
def __init__(self,子类及父类属性列表):
"""初始化父类的属性"""
super().__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.")
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
PS:Python2.7中的继承——函数super()需要两个实参:子类名
、对象self
# 父类
class Car(object):
def __init__(self, make, model, year):
--略--
# 子类
class ElectricCar(Car):
def __init__(self, make, model, year):
super(ElectricCar, self).__init__(make, model, year)
--略--
9.3 导入类
-
可以将类存储在模块中,然后在主程序中导入所需的模块。(一个模块可存储任意多个类)
- 操作与导入模块中的函数相同,使用import语句
- 可导入一个模块,使用
句点表示法
访问所需类 ——import
module_name - 可导入一个模块的特定类,若导入多个类则用逗号隔开——
from
module_nameimport
class_name - 可导入一个模块的所有类(使用星号),但不推荐,可能导致名称冲突——
from
module_nameimport *
(要从一个模块中导入很多类时,推荐导入整个模块,再使用句点表示法module_name.calss_name访问类)
# 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.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
# electric_car.py
"""一组可用于表示电动汽车的类"""
from car import Car
class Battery():
"""一次模拟电动汽车电瓶的简单尝试"""
def __init__(self, battery_size=60):
"""初始化电瓶的属性"""
self.battery_size = battery_size
def describe_battery(self):
"""打印一条描述电瓶容量的消息"""
print("This car has a " + str(self.battery_size) + "-kWh battery.")
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):
"""模拟电动汽车的独特之处"""
def __init__(self, make, model, year):
"""初始化父类的属性,再初始化电动汽车特有的属性"""
super().__init__(make, model, year)
self.battery = Battery()
# my_cars.py
from car import Car
from electric_car import ElectricCar
my_beetle = Car('volkswagen', 'beetle', 2016)
print(my_beetle.get_descriptive_name()) # 2016 Volkswagen Beetle
my_tesla = ElectricCar('tesla', 'roadster', 2016)
print(my_tesla.get_descriptive_name()) # 2016 Tesla Roadster
9.4 Python标准库
-
Python标准库是一组模块,可直接通过import使用。
-
Eg:模块collections中的OrderedDict类
- OrderedDict实例的行为几乎与字典相同,区别只在于记录了
键-值对
的添加顺序。 - 兼具列表和字典的主要优点(将信息关联起来的同时保留原来的顺序)
from collections import OrderedDict favorite_languages = OrderedDict() favorite_languages['jen'] = 'python' favorite_languages['sarah'] = 'c' favorite_languages['edward'] = 'ruby' favorite_languages['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. # Edward's favorite language is Ruby. # Phil's favorite language is Python.
- ⚠️ 这个在python3中没有用的必要,因为除了集合set外,列表和字典都能保留原来的顺序了。
- OrderedDict实例的行为几乎与字典相同,区别只在于记录了
-
模块random的choice函数
from random import choice choice(seq) # 参数seq ———— 列表、元组或字符串 # 实例 import random print("choice([1, 2, 3, 5, 9]) : ", random.choice([1, 2, 3, 5, 9])) print("choice('A String') : ", random.choice('A String')) # 输出: # choice([1, 2, 3, 5, 9]) : 5 # choice('A String') : S
-
模块random的random函数
random() 函数无参数;返回随机生成的一个实数,它在[0,1)范围内。
import random import string # 随机整数: print(random.randint(1,50)) # [1,50] # 随机选取0到100间的偶数: print(random.randrange(0, 101, 2)) # [0,101) 步长2 print(random.choice(range(0, 101, 2))) # 随机浮点数: print(random.random()) # [0,1) print(random.uniform(1, 10)) # [1,10] # 随机字符: print(random.choice('abcdefghijklmnopqrstuvwxyz!@#$%^&*()')) # 多个字符中生成指定数量的随机字符: print(random.sample('zyxwvutsrqponmlkjihgfedcba',5)) # 从a-z A-Z 0-9生成指定数量的随机字符: ran_str = ''.join(random.sample(string.ascii_letters + string.digits, 8)) print(ran_str) # 多个字符中选取指定数量的字符组成新字符串: print( ''.join(random.sample(['z','y','x','w','v','u','t','s','r','q','p','o','n','m','l','k','j','i','h','g','f','e','d','c','b','a'], 5))) # 随机选取字符串: print random.choice(['剪刀', '石头', '布']) # 打乱排序 items = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0] print random.shuffle(items)
PS:range(a, b)生成[a,b);list切片 list[start : stop] 也是包括start,不包括stop
-
模块datetime的datetime类中的函数
strptime()
——将日期字符串转为表示相应日期的对象- 参数1:日期字符串
- 参数2:要设置的日期格式
实参 含义 %Y 四位的年份,Eg:2015 %y 两位的年份,Eg:15 %m 用数字表示的月份(01~12) %d 用数字表示月份中的一天(01~31) %A 星期的名字,Eg:Monday %B 月份名,Eg:January %H 24小时制的小时数(00~23) %I(是大写的i) 12小时制的小时数(01~12) %M 分钟数(00~59) %S 秒数(00~59) %p am或pm from datetime import datetime first_date = datetime.strptime('2014-7-1', '%Y-%m-%d') print(first_date) # 2014-07-01 00:00:00
9.5 类编码风格
- 类名中每个单词首字母大写,不使用下划线;实例名和模块名都小写,单词之间加下划线。
- 类定义后跟文档字符串:简要描述类的功能;模块后跟文档字符串:简要描述其中的类功能;函数定义后跟文档字符串:简要描述函数的功能。
- 类中,使用一个空行来分隔方法;模块中,使用两个空行来分隔类。
- 先编写导入标准库模块中的import语句,再添加一个空行,导入自己编写的模块的import语句。
小结
变量、函数名、实例名、模块名都小写,单词间用下划线分隔。
类名采用驼峰命名法,各单词首字母大写,不用下划线。
常量名都大写,单词间用下划线分隔。
第十章 文件和异常
10.1 读取文件
Eg:pi.txt文件

-
文件路径
- 相对路径(相对于当前运行的程序所在目录)
-
在Linux和OS X中:with open('text_files/filename.txt') as file_object:
-
在Windows中(使用反斜杠\):with open('text_files\filename.txt' ) as file_object:
(显示文件路径时是反斜杠,但在代码证仍可以使用斜杠,若使用反斜杠则要转义)
-
- 绝对路径
- 相对路径(相对于当前运行的程序所在目录)
-
读取文本文件时,Python将其中的所有文本都解读为字符串。
- 若需转换为数值 ——
int(变量)
将字符串转换为整数,float(变量)
将字符串转换为浮点数
- 若需转换为数值 ——
10.1.1 读取整个文件——read()
-
函数
open(file_name)
会在当前执行文件所在目录中查找指定文件,返回一个表示文件的对象。 -
使用关键词
with
则无需访问文件后将其关闭(调用close()函数),Python会自动在合适时将其关闭。 -
函数
read()
将读取文件的全部内容,并返回一个字符串。PS:read()到达文件末尾时会返回一个空字符串,此空字符串显示出来是个空行。
with open('pi.txt') as file_object:
contents = file_object.read()
print(contents)
print(len(contents))
输出:

⚠️ 为什么有38个字符?
答:content为'3.1415926535\n 8979323846\n 2643383279'(中间空的是两个字符)
PS:之所以最后有一个空行,是因为print语句会加上一个换行符\n
10.1.2 逐行读取
- 要以逐行的方式检查文件,可对文件对象使用for循环:
with open('pi.txt') as file_object:
for line in file_object:
print(line)
输出:

⚠️ 为什么中间会出现空白行?
答:因为pi.txt文件中每行后有一个换行符\n,而print语句又会加上一个换行符\n,故出现了空白行。
(可通过在print语句中使用rstrip()函数,消除文件每行末尾的换行符,来消除空白行)
with open('pi.txt') as file_object: for line in file_object: print(line.rstrip()) # 输出: # 3.1415926535 # 8979323846 # 2643383279
10.1.3 将各行存储在列表中——readlines()
- 使用关键词
with
时,open()返回的文件对象只能在with代码块内使用。 - 使用函数
readlines()
从文件中读取每一行,最终返回一个列表。则将之存储在一个变量中,就可在with代码块外使用此列表。
with open('pi.txt') as file_object:
lines = file_object.readlines()
pi_string = ''
for line in lines:
pi_string += line.strip() # strip能剔除pi.txt中每行的换行和头部空格
print(pi_string) # 3.141592653589793238462643383279
print(len(pi_string)) # 32
10.1.4 取文件前x个字符 —— 使用切片
# pi_million_digits.txt中圆周率精确到小数点后1 000 000位
with open('pi_million_digits.txt') as file_object:
lines = file_object.readlines()
pi_string = ''
for line in lines:
pi_string += line.strip()
print(pi_string[:52] + "...") # 3.14159265358979323846264338327950288419716939937510...
print(len(pi_string)) # 1000002
10.2 写入文件
- 读取写入文件都使用open函数打开文件 ——
open(file_name, [mode],[encoding])
- 第一个形参 file_name:要打开的文件名称,不可省略。
- 第二个形参mode:指定文件读打开的模式——读取模式('r'),写入模式('w'),附加模式('a'),读取写入模式('r+')。省略时默认为读取模式。
- 若要写入的文件不存在,open()函数将自动创建它;若要读入的文件不存在,则会报错FileNotFoundError异常。
- 写入模式('w')时,若文件已存在,会清空文件内容;若不希望清空内容,使用附加模式('a')。
- 第三个参数 encoding:在系统默认编码与要读取文件使用的编码不一致时,需填写Eg:encoding='utf-8'
- 写入文件 ——
write()
- 函数write()不会自动在文本末尾添加换行符,需要你自己加\n
- Python只能将字符串写入文本文件,若要讲数值数据存储在文本中,需先使用
str(变量)
将其转换为字符串格式。
filename = 'programming.txt'
with open(filename, 'w') as file_object:
file_object.write("I love programming.\n")
file_object.write("I love creating new games.")
# programming.txt:
# I love programming.
# I love creating new games.
10.3 异常
-
异常
是一种特殊的对象,Python使用它来管理程序执行期间发生的错误。(每当发生让Python不知所措的错误时,它都会创建一个异常对象。)
-
若不对产生的异常进行处理,程序将停止,并显示一个trackback,其中包含有关异常的报告。
-
异常需使用
try-except
代码块 或try-except-else
代码块进行处理。-
try代码块:存放 可能引发异常 的代码
-
except代码块:存放 发生指定异常时 需执行的代码
-
若Python尝试运行try代码块中的代码时发生了except指定的异常,执行except代码块内容
-
可使用
pass语句
,让Python在发生指定异常时什么都不做,不出现traceback也不产生任何输出。(pass语句也算是一种对异常的处理,还充当了占位符,提醒你程序的某个地方啥都没做,且以后也许需要在这里做些什么)
-
else代码块:存放当 try代码块成功执行时 才需要执行的代码
-
-
若程序运行不产生异常,执行完try块后会跳过except块,执行后续代码;
否则,会直接查找except块并执行其中代码,然后执行后续代码(但try块中未执行的部分不再执行)。
(所以try-except-else可用try-except代替,只需将else块中内容放在try快中,但是有else代码块会使代码逻辑更清晰)
# 处理 ZeroDivisionError 异常
print("输入被除数和输出,将给出二者的商。")
print("输入 'q' 可终止程序。")
while True:
first_number = input("\n被除数: ")
if first_number == 'q':
break
second_number = input("除数: ")
try:
answer = int(first_number) / int(second_number)
except ZeroDivisionError:
print("不能被0除!")
else:
print(answer)
# 等价程序
print("输入被除数和除数,将给出二者的商。")
print("输入 'q' 可终止程序。")
while True:
first_number = input("\n被除数: ")
if first_number == 'q':
break
second_number = input("除数: ")
try:
answer = int(first_number) / int(second_number)
print(answer)
except ZeroDivisionError:
print("不能被0除!")
# 处理 FileNotFoundError 异常
def count_words(filename):
"""计算一个文件大致包含多少个单词"""
try:
with open(filename, encoding='utf-8') as f_obj:
contents = f_obj.read()
except FileNotFoundError:
pass
else:
# 计算文件大致包含多少个单词
words = contents.split()
num_words = len(words)
print("文件 " + filename + " 有大约 " + str(num_words) + " 个英文单词。")
filenames = ['alice.txt', 'siddhartha.txt', 'moby_dick.txt', 'little_women.txt'] # 其中siddhartha.txt不存在
for filename in filenames:
count_words(filename)
# 输出
# 文件 alice.txt 有大约 29461 个英文单词。
# 文件 moby_dick.txt 有大约 215136 个英文单词。
# 文件 little_women.txt 有大约 189079 个英文单词。
10.4 存储数据
-
使用模块
json
存储数据-
模块
json
可将给简单的Python数据结构(列表、字典)转储到文件中,并在程序加载文件时将数据加载到数据结构。还能与其他编程语言的人分享数据。
-
使用文件扩展名
.json
来指出文件存储的数据为JSON格式。
-
-
存储数据 ——
json.dump(data, file_object, indent=)
- 接受两个实参:要存储的数据、用于存储数据的文件对象【必填】
- 参数 indent=4:让 dump() 使用与数据结构匹配的缩进量来设置数据的格式。
-
读取数据 ——
json.load(file_object)
- 将数据转换为 Python 能处理的格式
import json numbers = [2, 3, 5, 7, 11, 13] filename = 'numbers.json' # 存储数据 with open(filename, 'w') as f_obj: json.dump(numbers, f_obj) # 读取数据 with open(filename) as f_obj: numbers = json.load(f_obj) print(numbers) # [2, 3, 5, 7, 11, 13]
实例:
import json def get_stored_username(): """如果存储了用户名,就获取它""" filename = 'username.json' try: with open(filename) as f_obj: username = json.load(f_obj) except FileNotFoundError: return None else: return username def get_new_username(): """提示用户输入用户名""" username = input("What is your name? ") filename = 'username.json' with open(filename, 'w') as f_obj: json.dump(username, f_obj) return username def greet_user(): """问候用户,并指出其名字""" username = get_stored_username() if username: print("Welcome back, " + username + "!") else: username = get_new_username() print("We'll remember you when you come back, " + username + "!") greet_user()
-
比较
json.dumps
,json.loads
和json.dump
,json.load
-
json.dumps
,json.loads
进行Python的数据结构和JSON格式之间的转换import json # Python数据结构 -> JSON data = { 'name' : 'ACME', 'shares' : 100, 'price' : 542.23 } json_str = json.dumps(data) # JSON -> Python数据结构 data = json.loads(json_str)
-
json.dump
,json.load
将Python的数据结构存储到JSON文件,或从JSON文件中读取数据
-
PS:重构
——代码能正确运行,但通过将其划分为一系列完成具体工作的函数还可以改进,此过程称为重构。
(目的在于让代码更清晰、更容易扩展)
第十一章 测试代码
-
单元测试
:用于核实函数的某个方面没有问题。 -
测试用例
:是一组单元测试,这些单元测试一起核实函数在各种情况下的行为都符合要求。- 良好的测试用例应考虑函数可能收到的各种输入,包含针对所有这些情况的测试。
-
全覆盖式测试
:用例包含一整套单元测试,涵盖了各种可能的函数使用方式。- 最初只需针对代码的重要行为编写测试即可,等项目被广泛使用时再考虑全覆盖。
-
How为函数编写测试用例:
-
导入
unittest
模块以及要测试的函数; -
创建一个继承
unittest.TestCase
的类,此类可随意命名但最好包含Test
字样; -
在此类中编写一系列方法对函数行为的不同方面进行测试,测试方法必须以
test_
打头。(这样这些方法才会在运行测试代码时自动运行)
-
Python在unittest.TestCase类中提供了很多
断言方法
,可用于在测试方法中核实得到的结果是否与期望的结果一致。(测试方法中若要使用断言,要有self形参,通过
self.assertEqual()
方式使用断言) -
测试文件代码行最后执行
unittest.main()
让Python运行这个文件中的测试。
-
-
断言方法
能检查你认为应该满足的条件是否确实满足。若满足,则对程序行为的假设得到了确认,没有错误。否则,Python将引发异常。常见的6种断言方法如下:(使用需继承unittest.TestCase类)方法 用途 assertEqual(a, b) 核实a == b assertNotEqual(a, b) 核实a != b assertTrue(x) 核实x为True assertFalse(x) 核实x为False assertIn(item, list) 核实item在list中 assertNotIn(item, list) 核实item不在list中 -
方法
setUp()
- 若在测试类中写了setUp()方法,则Python将先运行它,再运行各个以test_打头的方法。
- setUp()让测试方法编写更容易:可在setUp()方法中创建一系列实例并设置它们的属性,再在测试方法中直接使用这些实例。(这些实例变量都需加上前缀self,即存储在测试类的属性中,因此可以在此类的任何地方使用)
-
运行测试用例时,每完成一个单元测试,Python都打印一个字符:
- 测试通过,打印一个句点
- 测试引发错误,打印一个E
- 测试导致断言失败,打印一个F
11.1 测试函数
# name_function.py
def get_formatted_name(first, last, middle=''):
"""生成整洁的姓名"""
if middle:
full_name = first + ' ' + middle + ' ' + last
else:
full_name = first + ' ' + last
return full_name.title()
import unittest
from name_function import get_formatted_name
class NamesTestCase(unittest.TestCase):
"""测试name_function.py """
def test_first_last_name(self):
"""能够正确地处理像Janis Joplin这样的姓名吗?"""
formatted_name = get_formatted_name('janis', 'joplin')
self.assertEqual(formatted_name, 'Janis Joplin')
def test_first_last_middle_name(self):
"""能够正确地处理像Wolfgang Amadeus Mozart这样的姓名吗?"""
formatted_name = get_formatted_name( 'wolfgang', 'mozart', 'amadeus')
self.assertEqual(formatted_name, 'Wolfgang Amadeus Mozart')
unittest.main()
11.2 测试类
# survey.py
class AnonymousSurvey():
"""收集匿名调查问卷的答案"""
def __init__(self, question):
"""存储一个问题,并为存储答案做准备"""
self.question = question
self.responses = []
def show_question(self):
"""显示调查问卷"""
print(question)
def store_response(self, new_response):
"""存储单份调查答卷"""
self.responses.append(new_response)
def show_results(self):
"""显示收集到的所有答卷"""
print("Survey results:")
for response in responses:
print('- ' + response)
import unittest
from survey import AnonymousSurvey
class TestAnonymousSurvey(unittest.TestCase):
"""针对AnonymousSurvey类的测试"""
def setUp(self):
"""创建一个调查对象和一组答案,供使用的测试方法使用"""
question = "What language did you first learn to speak?"
self.my_survey = AnonymousSurvey(question)
self.responses = ['English', 'Spanish', 'Mandarin']
def test_store_single_response(self):
"""测试单个答案会被妥善地存储"""
self.my_survey.store_response(self.responses[0])
self.assertIn(self.responses[0], self.my_survey.responses)
def test_store_three_responses(self):
"""测试三个答案会被妥善地存储"""
for response in self.responses:
self.my_survey.store_response(response)
for response in self.responses:
self.assertIn(response, self.my_survey.responses)
unittest.main()
此处:setUp()方法创建一个调查对象my_survey和一个答案列表responses。
存储二者的变量名都含前缀self(即存储在属性中),故可在这个类的任何地方使用。
本文作者:Joey-Wang
本文链接:https://www.cnblogs.com/joey-wang/p/14539910.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」