Python从入门到实践笔记(前十二章)
方法剔除字符串空白字符
末尾空白字符rstrip(),()内可放参数类型如chars用来剥离特定字符不放默认空格和换行符
开头lstrip()
两头strip()
并没有永久删除,需要重新给对应赋值就可永久覆盖
msg_kongbai=" rhz"
msg_kongbai_1="rhz "
msg_kongbai_2=" r h z "
print("开头空白剔除:"+msg_kongbai.lstrip()+"\n"+"末尾空白剔除:"+msg_kongbai_1.rstrip()+"\n"+"两头空白去除:"+msg_kongbai_2.strip())
整数的+-*/
python3中3/2=1.5与c语言有别,python2中表示整除与c类似
两个表示乘方运算 23=8
print(2+3**4)
在python中带小数点的数字都称为浮点数。
print(0.2+0.1)
str()函数将非字符串转化为字符串输出
age = 23
print(str(age))
print(23)
print('23')
列表[]
bicycles = ['trek','cannondale','redline']
print(bicycles)
访问列表元素,提供元素的索引或位置
print(bicycles[0])#---->trek
print(bicycles[-1])#---->redline
修改列表元素
bicycles[0]='nick'
print(bicycles[0])
在列表中添加新元素
1.在列表末尾添加新元素r,append()
bicycles.append('r')
2.insert(索引,'值')在任何位置加入新元素,原位置元素依次后移
bicycles.insert(0,'h')
3.删除列表中的元素
(1)知道元素在列表中的位置,del 列表名[索引]
del bicycles[0]
(2)pop()方法,列表就像一个栈,此法指弹出一个列表中栈顶的元素,且源列表中此元素已经被删除,英语:弹出(pop)
print(bicycles)
pop_bicycles = bicycles.pop()
(3)弹出(且删除源列表中此元素)任意位置的元素pop(索引)
pop_bicycles = bicycles.pop(0)
4.根据值删除元素,方法remove()
bicycles.append('h')
print(bicycles)
bicycles.remove('h')
"""remove仅删除第一个指定的值,如果要删除的值在列表中多次出现,可以使用循环来判断是否删除了所有的这样的值"""
3-4--->创建一个嘉宾名单
guest_name=['rhz','jay_chou',"Bazzi"]
print("嘉宾名单:"+guest_name+'\n'),写法错误,列表之前不能加str
print("嘉宾名单:")
print(guest_name)
3-5----->修改嘉宾名单
guest_name[2]='习主席'
print("嘉宾名单:")
print(guest_name)
3-6------>添加3位嘉宾
guest_name.append('陈奕迅')#末尾添加
guest_name.insert(0,'林志玲')#第一位插入
print("嘉宾名单:"+guest_name+'\n')
print("嘉宾名单:")
print(guest_name)
3-7,缩短名单
guest_sorry=guest_name.pop()
print("很抱歉,"+guest_sorry+'先生!'+'由于种种原因,您不能参加此次宴会!'+'\n')
guest_sorry=guest_name.pop()
print("很抱歉,"+guest_sorry'+'由于种种原因,您不能参加此次宴会!'+'\n')
guest_sorry=guest_name.pop()
print("很抱歉,"+guest_sorry'+'由于种种原因,您不能参加此次宴会!'+'\n')
print("恭喜您幸存!"+guest_name[0]+'\n')
print("恭喜您幸存!"+guest_name[1]+'\n')
del guest_name[1]
del guest_name[0]
print("结束"+guest_name+'\n')
3-8放眼世界
cities=['Canada','China','world','xz','usa']
print(cities)#原始顺序打印
sorted(cities)
print(cities)
cities.reverse()#cities.reverse()无返回值直接对原列表操作,直接print(cities.reverse())提示none
print(cities)#分开才可
cities.sort()
print(cities)
cities.sort(reverse=True)
print(cities)
3-9显示列表长度
print(str(len(cities)))#*len(cities)返回整型数据,需要str()转化为字符串输出
3.4spython中列表索引从0开始,但计算长度时从一开始,不用考虑差一,索引-1返回最后一个列表元素
my_1=['r','h','z']
print(my_1[-1])#输出z
print(my_1[2])#输出z
当发生索引错误:IndexError:..时请尝试打印列表长度,如果列表为空你索引个寂寞!
my_2=[]
print(my_2[1])#引发索引错误
操作列表
1.遍历整个列表之使用for循环,打印列表名单
test_forname=['rhz','jchou','ljj','xjp']#创建一个列表
for name in test_forname:
print(name)#从列表中取出一个名字,并给这些值找一个临时变量(任意定义但最好语义化)name住进去
name单数,names复数灵巧的使用更便于区分单元素列表多元素列表
2.for循环后缩进的代码都是循环的一部分,没有缩进的只执行一次
test_forname=['rhz','jchou','ljj','xjp']#创建一个列表
for name in test_forname:
print('Hello!'+name+'\n')
print('我只在最后出现!')
请不要编写不必要的缩进,否则报错
4.3创建数值列表,使用python自带工具
1.函数range()生成一系列数字
for value in range(1,5):
print(value)
差一输出,只会打印1~4的数字
2.range()创建数字列表
numbers = list(range(1,6))#list()输出一个数字列表
print(numbers)
range()指定步长
even_numbers = list(range(2,11,2))
print(even_numbers)#函数range()从2开始数,叠加2,直到达到或超过11
还可以这样用range()
squares = []
for value in range(1,11):
square = value2#做乘方运算 squares.append(square) #squares.append(value2),更简洁,未用到临时变量square,通常到完成之后我们再来考虑是否可以优化代码
print(squares)
"""我们首先考虑的是编写清晰易懂且能完成所需功能的代码,等到审核代码时,再考虑采用高效的方法"""
对数字列表执行简单的统计计算
digits = [1,2,3,4,5,6,7,8,9]
min(digits)
max(digits)
sum(digits)#python自带函数
对列表解析创建列表
squares = [value**2 for value in range(1,11)]
print(squares)
首先指定一个语义化的列表名(squares)
然后指定一个左方括号并定义一个表达式(value**2)用于生成你要储存到列表中的值
squares=[value**2
编写for循环把值------->递给(value**2)再以右方括号结束]
squares=[value**2 for value in range(1,11)]
此处for语句末尾没有冒号
4-3
for num in range(1,21)
print(num)
4-4
numbers = list(range(1,100001))
for num in numbers:
print(num)
max(numbers)
min(numbers)
sum(numbers)
4-6,奇数
numbers_js = list(range(1,21,2))
for num in numbers_js:
print(num)
3的倍数:创建一个列表,其中包含3~30内能被3整除的数字;再使用一个for循环将这个列表中的数字都打印出来
numbers_3 = list(range(3,31,3))
for num in numbers_3:
print(num)
'''第二种'''
number_3_1=[]
for num in range(3,31):
value = num+3
number_3_1.append(value)#临时变量value,并将他存到列表中
#number_3_1.append(value+3)#两种方法
print(number_3_1)
4-8 立方:将同一个数字乘三次称为立方。例如,在Python中,2的立方用2**3表示
请创建一个列表,其中包含前10个整数(即1~10)的立方,再使用一个for循环将这些立方数都打印出来。
numbers_4_8 = [value**3 for value in range(1,11)]
for num in numbers_4_8:
print(num)
4-9 立方解析:使用列表解析生成一个列表,其中包含前10个整数的立方。
numbers_4_8 = [value**3 for value in range(1,11)]
print(numbers_4_8)
使用列表的一部分,
处理列表的部分元素叫做切片
创建切片,与range()类似,指定第一个元素与最后一个元素+1的索引
players = ['1','2','3','4']
print(players[0:3])#打印列表的切片,前3名队员,输出格式也是列表,可以用来给列表生成子集
print(players[:4])#若第一个索引没有被你指定,则python自动从列表开头开始
print(players[0:])#自动终止于列表末尾
print(players[-3:])#负数索引返回离列表末尾相应距离的元素,切片players[-3:]输出名单最后三名队员
4.4.2
遍历列表
在for循环中使用切片
print("前三名运动员的名字是:")
for player in players[:3]:
print(str(player))
在很多情况下,切片都很有用。例如,编写游戏时,你可以在玩家退出游戏时将其最终得分加入到一个列表中。
然后,为获取该玩家的三个最高得分,你可以将该列表按降序排列,再创建一个只包含前三个得分的切片。处理数据时
可使用切片来进行批量处理;编写Web应用程序时,可使用切片来分页显示信息,并在每页显示数量合适的信息。
4.4.3复制列表
可根据既有列表创建全新的列表
([:])创建一个省略开头和结尾索引的切片即可复制整个列表
my_test_1= ['pizza','apple','banana']#创建一个列表
my_test_1_copyqiepian = my_test_1[:]#创建切片,并将它存储到变量my_test_1_copyqiepian中
print(my_test_1_copyqiepian)
print(my_test_1)
比较两者是否相同
倘若我们只是简单地将my_foods赋给friend_foods,就不能得到两个列表。
例如,下例演示了在不使用切片的情况下复制列表的情况:
my_foods = ['pizza', 'falafel', 'carrot cake']
这行不通
friend_foods = my_foods #此处的赋值实际上让Python将新变量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)
4—10
players = ['1','2','3','4']
print('前三个元素为:')
print(players[:3])
print('后三个元素为:')
print(players[-3:])
4-11
copy_players = players[:]
players.append('5')
copy_players.append('6')
for player in players:
print('初始运动员名单:')
print(player)
print('复制且加入后运动员名单:')
for copy_player in copy_players:
print(copy_player)
4.5元组
Python将不能修改的值称为不可变的,而不可变的列表被称为元组
1.定义元组
元组看起来就像是列表一样,可是元组是圆括号,访问元组也用索引
my_test_2 = (200,50)#元组定义一个矩形长宽不能改变为200,50
print(my_test_2[0])#打印方法与列表类似
修改元组的值:
my_test_2[0]=250
返回错误提示,故不能改变元组的值
2.遍历元组
for value in my_test_2:
print(value)
与遍历列表类似
3.修改元组变量
虽然不能修改元组的元素,但可以给存储元组的变量赋值。
my_test_2 = (200,50)#元组定义一个矩形长宽不能改变为200,50
print(my_test_2[0])#打印方法与列表类似
my_test_2 = (350,150)#元组定义一个矩形长宽不能改变为200,50
print(my_test_2[0])#打印方法与列表似
又如
dimensions = (200, 50)
print("Original dimensions:")
for dimension in dimensions:
print(dimension)
dimensions = (400, 100)
print("\nModified dimensions:")
for dimension in dimensions:
dimension = dimension +200
print(dimension)
'''即是用新的元组覆盖旧的元组,给元组变量赋值是合法的'''
元组相比于列表是更简单的数据结构,和c的全局变量功能类似
4-13
cafeteria = ('面条','米粉','荞面')
for foods in cafeteria:
print(foods)
cafeteria[0]='面包',测试修改元组
cafeteria = ('爱','和平','世界')#给元组变量重新赋值
for words in cafeteria:
print(words)
4.6设置代码格式
随着你编写的程序越来越长,有必要了解一些代码格式设置约定。
请花时间让你的代码尽可能易于阅读;
让代码易于阅读有助于你掌握程序是做什么的;
也可以帮助他人理解你编写的代码。
保持良好的书写习惯,才能保证后期维护轻松愉快
PEP 8建议每级缩进都使用四个空格,可使用制表符或键盘tab,这既可提高可读性,又留下了足够的多级缩进空间。
'''
4.6.2 缩进
PEP 8建议每级缩进都使用四个空格,这既可提高可读性,又留下了足够的多级缩进空间。
在字处理文档中,大家常常使用制表符而不是空格来缩进。
对于字处理文档来说,这样做的效果很好,但混合使用制表符和空格会让Python解释器感到迷惑。
每款文本编辑器都提供了一种设置,可将输入的制表符转换为指定数量的空格。
你在编写代码时应该使用制表符键,但一定要对编辑器进行设置,使其在文档中插入空格而不是制表符。
在程序中混合使用制表符和空格可能导致极难解决的问题。
如果你混合使用了制表符和空格,可将文件中所有的制表符转换为空格,大多数编辑器都提供了这样的功能。
'''
3.行长
很多Python程序员都建议每行不超过80字符
专业程序员通常会在同一个屏幕上打开多个文件,使用标准行长可以让他们在屏幕上并排打开两三个文件时能同时看到各个文件的完整行。
PEP 8中有关行长的指南并非不可逾越的红线,有些小组将最大行长设置为99字符。
在学习期间,你不用过多地考虑代码的行长,但别忘了,协作编写程序时,大家几乎都遵守PEP 8指南。
在大多数编辑器中,都可设置一个视觉标志——通常是一条竖线,让你知道不能越过的界线在什么地方。
4.空行
空行不会影响代码的运行,但会影响代码的可读性。Python解释器根据水平缩进情况来解读代码,但不关心垂直间距。
空行可以分隔程序不同的部分,但不可以滥用
5.其他格式设置指南,PEP 8中有介绍复杂
4-14 PEP 8:请访问https://python.org/dev/peps/pep-0008/,阅读PEP 8格式设置指南。
当前,这些指南适用的不多,但你可以大致浏览一下。
'''
4-15 代码审核:从本章编写的程序中选择三个,根据PEP 8指南对它们进行修改。
·每级缩进都使用四个空格。对你使用的文本编辑器进行设置,使其在你按Tab键时都插入四个空格;
如果你还没有这样做,现在就去做吧(有关如何设置,请参阅附录B)。
·每行都不要超过80字符。对你使用的编辑器进行设置,使其在第80个字符处显示一条垂直参考线。
·不要在程序文件中过多地使用空行。
'''
vs中好像TAB默认就是四个空格
if语句
5.1
cars = ['audi','bmw','subaru']
for car in cars:
if car == 'bmw':
print(car.upper())
else:
print(car.title())
当且仅当为宝马时全大写
2.条件测试
1.检查是否相等
car = 'bmw'
car == 'bmw'
car=='mss'
"""输出True和False"""
一个等号是陈述两个等号是发问
如此处:变量car的值是'bmw'吗?
5.2.2检查是否相等时考虑大小写
python中检查是否相等时会区分大小写
car = 'Audi'
car == 'audi'
False
为了使二者相等可将大写转化为小写,在进行比较
car = 'Rhz'
car.lower() == 'rhz'
True
PS:函数lower()不会修改存储在变量car中的值,所以这样比较不会影响原来的变量
car = 'Rhz'
car.lower() == 'rhz'
True
car == 'Rhz'
True
网站可采用类似的方式让用户输入的数据符合特定的格式,如网站用大小写转换以确保数据库中不存在类似的用户名
来确保此用户名独一无二
5.2.3检查是否不相等(!=)
类似相等,有时候用不相等的效率更高,略
5.2.4比较数字
条件语句中可包含各种数学比较,如小于、小于等于、大于、大于等于
在if语句中可使用各种数学比较,这让你能够直接检查关心的条件。
5.2.5检查多个条件
有时你想同时检查多个条件都为True时才执行某一操作,此时可用关键字and和or
1.and,用来检查多个条件
age_0 = 22
age_1 = 18
age_0 >= 21 and age_1 >= 21
False
联想C语言的&&及类似的条件运算符
为改善可读性,可将每个测试都分别放在一对括号内,但并非必须这样做。
如果你使用括号,测试将类似于下面这样:
(age_0 >= 21) and (age_1 >= 21)
2.使用or检查多个条件
联想c语言的||运算符,至少一个条件满足就能通过整个测试
age_0 = 22
age_1 = 18
age_0 >= 21 and age_1 >= 21
True
5.2.6检查特定值是否包含在列表中
使用关键字in,判断特定的值是否已包含在列表中
my_test_3 = ['r','h','z']
'z' in my_test_3
True
与此对应检查是否不在列表中就使用关键字not in
如检查某个用户是否存在于黑名单中,如果不存在就可以发言
banned_users = ['andrew', 'carolina', 'david']
user = 'marie'
if user not in banned_users: ❶
print(user.title()+", 你不在黑名单中,你可以发言!.")
5.2.8 布尔表达式
条件测试的别名,结果要么为True,要么为False
布尔值通常用于记录条件,如游戏是否正在运行,或用户是否可以编辑网站内容
game_active = True
can_edit = False
在跟踪程序状态或程序中重要的条件方面,布尔值提供了一种高效的方式。
#
car = ['1','2','3','Car_1','Bmw','bmw','tesla']
Bmw = 'Bmw'
Bmw.lower() in car
'1' != '2'
1 != 2
(1>=2) and (2<=3) (1>=2) or (2<=3)
'bmw' not in car
5.3if语句
1.最简单的if语句包含一个测试和一个操作
if conditional_test:
do something
age = 19
if age >= 18:
print('你已经成年了!')
2.if-else
age = 19
if age >= 18:
print('你已经成年了!')
else:
print('你还没有成年')
"""仅仅执行两种情况的一种"""
3.if-elif-else
可检查超过两个的情况,依次对每个进行条件测试,通过测试后将执行紧跟其后的代码,并跳过余下的测试
age = 19
if age >= 18:
print('你已经成年了!')
elif age < 18:
print('你还没成年')
else:
print("请输入正确的年龄!")
5.3.4使用多个elif代码块
如根据年龄确定门票价格
age = 12
if age < 4:
price = 0
elif age < 18:
price = 5
elif age < 65:
price = 10
else:
price = 5
print("你的门票价格为:"+str(price)+'元。')
5.3.5省略else代码块
并不要求if-elif结构后面必须有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)+".")
处的elif代码块在顾客的年龄超过65(含)时,将价格设置为5美元,这比使用else代码块更清晰些。
经过这样的修改后,每个代码块都仅在通过了相应的测试时才会执行。
else是一条包罗万象的语句,只要不满足任何if或elif中的条件测试,其中的代码就会执行,这可能会引入无效甚至恶意的数据。
如果知道最终要测试的条件,应考虑使用一个elif代码块来代替else代码块。
5.3.5测试多个条件
if-elif-else结构虽好,但终归只能满足一个特定条件下的执行,其余代码直接跳过
有时我们必须检查所有的条件,这个时候我们应该使用简单的if语句,
在可能有多个条件为True时,且每个True时都要采取相应措施适合就用简简单单的True
'''
总之,如果你在条件测试时若,只想执行一个代码块,就使用if-elif-else结构;如果要运行多个代码块,就使用一系列独立的if语句。
'''
5-3外星人颜色,射杀外星人,若外星人是绿色则指明玩家获得五个点
alien_color = green
if alien_color == 'green':
print("恭喜你获得五个点")
elif alien_color == 'yellow':
print('sorry')
else:
print('game over!')
5-6 人生不同阶段
age = 10
if age < 10: print('小朋友快去写作业!') elif (age>10) and(age<50):
print("中年朋友你好")
else:
print("你应该是老年朋友吧!")
5-7
shuiguo = ['苹果','香蕉',"梨子",'荔枝']
zuiai = ['苹果','西瓜','荔枝']
jinhuo = []
if '苹果' in shuiguo:
print("苹果在列表中")
for shuiguos in zuiai:
if shuiguos in shuiguo:
print("你喜欢吃的:"+shuiguos+'在我们的列表中')
else:
print('我们没有这种水果,但我们将他添加到jinhuo中,稍后你可调用')
jinhuo.append(shuiguos)
print(jinhuo)
5.4使用if语句处理列表
requested_toppings = []# ❶
if requested_toppings:# ❷
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?")
使用此法来判断列表是否为空,在❷处我们进行了简单检查,而不是直接执行for循环。
在if语句中将列表名用在条件表达式中时,Python将在列表至少包含一个元素时返回True,并在列表为空时返回False。
与c语言非0时执行类似,True非0,False为0
5.4.3使用多个列表
shuiguo = ['苹果','香蕉',"梨子",'荔枝']
zuiai = ['苹果','西瓜','荔枝']
jinhuo = []
if '苹果' in shuiguo:
print("苹果在列表中")
for shuiguos in zuiai:
if shuiguos in shuiguo:
print("你喜欢吃的:"+shuiguos+'在我们的列表中')
else:
print('我们没有这种水果,但我们将他添加到jinhuo中,稍后你可调用')
jinhuo.append(shuiguos)
我们定义了3个列表,在第一个循环中我们遍历位于最爱中的每一个元素,并且每次遍历时都检查它是否位于shuiguo列表中
如果不位于水果列表中,就把他添加进进货列表中,通过为数不多的几行代码,我们高效的处理了一种真实的情形
5-8 以特殊的方式跟管理员打招呼
users = ['rhz','admin','小东','小航','小明']#创建一个包含4个用户名的列表
for user in users:
if user == 'admin':
print('你好超级管理员!')
else:
print('你好!'+user)
5-9 处理没有用户的情形
if users:
print('已经为你删除了所有元素!')
del users[:]
print("已经删完了大哥!")
print(users)
5-10检查用户名
网站独一无二的用户名
current_users = ['rhz','熊大','熊二','光头强']#创建一个包含五个用户名的列表
new_users = ['RHZ','熊大','吉吉国王','超人','喜羊羊']#创建另一个列表,模拟注册
for users in new_users:
if (users) or (users.lower()) in current_users:
print(users+'-->用户名已经被使用')
else:
print(users+'此用户名可用!')
输出错误
网站独一无二的用户名
current_users = ['rhz','xd','x2','Gtq','XYY']#创建一个包含五个用户名的列表
new_users = ['RHZ','xd','jjgw','cr','xyy']#创建另一个列表,模拟注册
for users in new_users:
print(users.lower()+users.upper())
if users.lower() in current_users or users.upper() in current_users:
print(users+'-->用户名已经被使用')
else:
print(users+'此用户名可用!')
输出正确
current_users = ['rhz','xX大','熊x二','光头强','xYxz']
创建一个包含五个用户名,且用户名大小写都有的列表
new_users = ['RHZ','xx大','吉吉国王','超人','喜羊羊','xyxz']
创建另一个列表,模拟注册
copy_users = [users.lower() for users in current_users]
大小写处理,把current_users全部转化为小写
制作列表的副本,且副本中的所有元素皆为小写,解析创建列表
副本既可以避免原列表被改变,也可以方便新注册用户与此相比较
for users in new_users:
if users.lower() in copy_users:
#把users转化为小写方便与副本比较
print(users+'-->用户名已经被使用')
else:
print(users+'-->此用户名可用!')
5-11序数
shuzi = list(range(1,10))
for num in shuzi:
if num ==1 or num == 3:
print(str(num)+"st")
elif num == 2:
print(str(num)+'nd')
else:
print(str(num)+'th')
5.5 设置if语句的格式:
PEP 8提供的唯一建议是,在诸如==、>=和<=等比较运算符两边各添加一个空格,例如,if age < 4:要比if age<4:好。
这样的空格不会影响Python对代码的解读,而只是让代码阅读起来更容易。
第六章 字典
1.一个简单的字典
alien_0 = {'color':'green','points':5}
print(alien_0['color'])#green
print(alien_0['points'])#5
2.使用字典
python中字典是一系列的键对值,每个键对应一个值,你可以使用键来访问与之相关联的值
与键相关联的值可以是数字、字符串、列表乃至字典。可将python对象用作字典的值
alien_0 = {'color':'green','分数':'5分'}
键--值对是两个相关联的值,键和值之间用':'分隔,键值对间用','分隔开
2_1
获取字典中的值,依次指定字典名和放在方括号内的键
alien_0 = {'color':'green'}
print(alien_0['color'])
返回green
"""
现在,你可以访问外星人alien_0的颜色和点数。
如果玩家射杀了这个外星人,你就可以使用下面的代码来确定玩家应获得多少个点:
alien_0 = {'color': 'green', 'points': 5}
new_points = alien_0['points'] ❶
print("You just earned "+str(new_points)+" points!") ❷
上述代码首先定义了一个字典,然后从这个字典中获取与键'points'相关联的值(见❶),
并将这个值存储在变量new_points中。接下来,将这个整数转换为字符串,并打印一条消息,指出玩家获得了多少个点(见❷):
You just earned 5 points!
如果你在有外星人被射杀时都运行这段代码,就会获取该外星人的点数。
"""
2_2添加键--值对
字典是一种动态结构,可随时在其中添加键—值对。
要添加键—值对,可依次指定字典名、用方括号括起的键和相关联的值。
alien_0 = {'颜色':'绿色','获得分数':'5'}
print(alien_0)
alien_0['x坐标'] = 0#在字典alien_0中新增一个键-值对,其中的键名为:'x坐标',值为:0
alien_0['y坐标'] = 25#在字典alien_0中新增一个键-值对,其中的键名为:'y坐标',值为:25
print(alien_0)
键值对的排列顺序与你的添加顺序没有关系,python只关心键和值之间的关联关系
3.创建一个空字典
alien_0 = {}#空字典
alien_0['颜色'] = '红色'#在字典中添加一组键对值
"""
使用字典来存储用户提供的数据或在编写能自动生成大量键—值对的代码时,通常都需要先定义一个空字典。
"""
4.修改字典中的值
alien_0 = {'颜色':'绿色','获得分数':'5'}
alien_0['颜色'] = 'yellow'
例2
对一个能够以不同速度移动的外星人的位置进行跟踪。
为此,我们将存储该外星人的当前速度,并据此确定该外星人将向右移动多远:
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']))
这种技术很棒:通过修改外星人字典中的值,可改变外星人的行为。
例如,要将这个速度中等的外星人变成速度很快的外星人,可添加如下代码行:
alien_0['speed'] = 'fast'
这样,再次运行这些代码时,其中的if-elif-else结构将把一个更大的值赋给变量x_increment。
5.删除键值对
使用del语句,且必须指定字典名和要删除的键
alien_0 = {'颜色':'绿色','获得分数':'5'}
print(alien_0)
del alien_0['颜色']#永久删除键颜色,且其对应的值绿色也被删除
6.由类似对象组成的字典
6-1使用字典存储一个熟人的信息
my_friend = {
'姓':'周'
'名':'杰伦'
'城市':"台湾"
'年龄':'40多'
}
print(my_friend)
6—3,Python字典可用于模拟现实生活中的字典,但为避免混淆,我们将后者称为词汇表。
code_language = {'c':'最擅长','e':"听说",'java':'不擅长','python':'正在学'}
6.3 遍历字典
3_1 遍历所有的键值对
user_0 = {
'username': 'efermi',
'first': 'enrico',
'last': 'fermi',
}
for key,value in user_0.items():
print('\nKey:'+key)
print('Value:'+value)
要编写用于遍历字典的for循环,可声明两个变量,用于存储键值对中的键和值
for k,v in user_0.items()
方法items(),返回一个键值对列表。
print(user_0.items())---->dict_items([('username', 'efermi'), ('first', 'enrico'), ('last', 'fermi')])
注意,即便遍历字典时,键—值对的返回顺序也与存储顺序不同。
Python不关心键—值对的存储顺序,而只跟踪键和值之间的关联关系。
2.遍历字典中的所有键
在不需要使用字典中的值时,方法keys()很有用。
下面来遍历字典favorite_languages,并将每个被调查者的名字打印
favorite_languages = {
'jen': 'python',
'sarah': 'c',
'edward': 'ruby',
'phil': 'python',
}
for name in favorite_languages.keys():
print(name.title())
print(favorite_languages.keys())--->dict_keys(['jen', 'sarah', 'edward', 'phil'])
处的代码行让Python提取字典favorite_languages中的所有键,并依次将它们存储到变量name中
遍历字典时会默认遍历所有的键,因此如果将favorite_languages.keys()换成favorite_languages()输出将不变
3.3按顺序遍历字典中的所有键
由于获取字典元素时获取顺序的不可预测性,所以如果我们要以特定的顺序进行返回
我们可以使用for循环来对返回的键进行排序
函数sorted()获得按特定顺序排列的(键-列表)的副本
favorite_languages = {
'jen': 'python',
'sarah': 'c',
'edward': 'ruby',
'phil': 'python',
}
for name in sorted(favorite_languages.keys()):
print(name.title()+", thank you for taking the poll.")
print(favorite_languages.keys())--->dict_keys(['jen', 'sarah', 'edward', 'phil'])-->一个隐秘的却又不完全是列表的列表
让python列出字典中的所有键
调用了函数sorted(),在遍历前对这个列表进行排序
3_4遍历字典中的所有值
方法是values()
favorite_languages = {
'jen': 'python',
'sarah': 'c',
'edward': 'ruby',
'phil': 'python',
}
print(favorite_languages.values())
返回一个值列表,而不包含任何键
dict_values(['python', 'c', '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())
#
6-5河流
rivers = {
'尼罗河' : '埃及',#","不要忘记了
'长江' : '中国',
'密西西比河' :"美国"
}
for river in rivers.keys():
print(river+'流经'+rivers[river]+'\n')
best_river =['长江']
for river in rivers.keys():
if river in best_river:
print('世界上最好的国家'+rivers[river]+', 有最受世界欢迎的河流'+river+'!\n')
else:
print('对不起:'+rivers[river]+',请继续努力!和你们的河流:'+river+'一起!\n')
6.4嵌套
将一系列字典存储在列表中,或将列表作为值存储在字典中,这称为嵌套。
你可以在字典中嵌套列表,列表中嵌套字典,甚至字典嵌套字典
4_1字典列表
字典alien_0包含一个外星人的各种信息,但无法储存第二个外星人的信息
那么如何储存多个外星人的信息呢?
1.创建一个外星人列表
alien_0 = {
'颜色':'绿色',
'击杀所得分数' : "5"
}
alien_1 = {
'颜色' : '黄色',
'击杀所得分数' : '10'
}
alien_2 = {
'颜色' : '红色',
'击杀所得分数' : '15'
}
其中每个外星人都是一个字典
aliens = [alien_0,alien_1,alien_2]
print(aliens)--->[{'颜色': '绿色', '击杀所得分数': '5'}, {'颜色': '黄色', '击杀所得分数': '10'}, {'颜色': '
把所有的外星人放进列表(aliens)中
for alien in aliens:
print(alien)
遍历列表打印每个外星人
使用range()生成30个外星人
创建一个用于存储外星人的空列表
aliens = []
创建30个绿色的外星人
for alien_number in range(30):
#range()返回一系列数字,其唯一的用途是告诉Python我们要重复这个循环多少次。
new_alien = {
'颜色:':'绿色',
'击杀所得分数':'5'
'移动速度':'慢'}
aliens.append(new_alien)#每循环一次创建一个机器人
使用切片打印显示前五个外星人
for alien in aliens [:5]:
print(alien)
print('…')
显示创建了多少个外星人
print('外星人的个数:'+str(len(aliens)))
将前三个外星人更改
for alien in aliens[:3]:
if alien['颜色'== '绿色']:
alien['cocor'] = '红色'#就算被存入列表,他也是一个字典,单独访问修改其中元素,就直接用修改字典的方法
略
把字典装进列表这种方法,很适用于创建用户列表,且包含了每个用户的信息在内,
在这个列表中所有字典的结构都相同,因此你可以遍历这个列表,并以相同的方式处理其中的每个字典
4_2在字典中存储列表
存储点菜信息
shopping = {
'商品': ['凉面','米粉','面条','粥'
'口味': ['辣', '清淡','微辣','辣'],
}
概述所点的菜
for shop in shopping['商品']:
print("你点了一份 "+shopping['商品']+"! "+
"我们有这些口味:")
for topping in pizza['口味']:
print("\t"+topping)
每当我们需要在字典中将一个键关联到多个值时,都可以在字典中嵌套一个列表
for 中套for输出每个人喜欢的多种事物
favorite_languages = {
'jen': ['python', 'ruby'],
'sarah': ['c'],
'edward': ['ruby', 'go'],
'phil': ['python', 'haskell'],
}
for name, languages in favorite_languages.items():
print("\n"+name.title()+"'s favorite languages are:")
for language in languages:
print("\t"+language.title())
为进一步改进这个程序,可在遍历字典的for循环开头添加一条if语句,
通过查看len(languages)的值来确定当前的被调查者喜欢的语言是否有多种。
如果他喜欢的语言有多种,就像以前一样显示输出;
如果只有一种,就相应修改输出的措辞,如显示Sarah's favorite language is only C.
4.3在字典中存储字典
可在字典中嵌套字典,但这样做时,代码可能很快复杂起来。
例如,如果有多个网站用户,每个都有独特的用户名,可在字典中将用户名作为键
然后将每位用户的信息存储在一个字典中,并将该字典作为与用户名相关联的值
users = {
'jay_chou': {
'姓':'周',
'名':'杰伦',
'国籍':'中国',
},
'max_kim':{
'姓':'r'
'名':'hz'
'国籍':'中国'
},
}#定义一个名为users的字典,其中包含两个键:用户名'jay_chou’和'max_kim'
与每个键相关联的值都是一个字典,其中包括用户的姓名国籍
for username,user_info in users.items():
#items()返回一个键值对列表,这里的username-->键,user_info可叫做内部字典
print('\n姓名:'+username)
full_name = user_info['姓']+' '+user_info['名']
location = user_info['国籍']
print('\n全名:'+full_name)
print("来自:"+location)
}
'''
请注意,表示每位用户的字典的结构都相同,虽然Python并没有这样的要求,但这使得嵌套的字典处理起来更容易。
倘若表示每位用户的字典都包含不同的键,for循环内部的代码将更复杂。
'''
6-9喜欢的地方
favorite_places = {
'rhz':{
'重庆':'最爱',
'云南':'其次',
'西藏':'第二',
},
'jay':{
'重庆':'最爱',
'台湾':'最爱',
}
}
for name,love_place in favorite_places.items():
print(name+'喜欢的地方有'+love_place['重庆'])
6-8宠物
pet_1 = {
'宠物名':'金毛',
'主人':'rhz'
}
pet_2 = {
'宠物名':'萨摩耶',
'主人':'rhz'
}
pet_3 = {
'宠物名':'阿拉斯加',
'主人':'rhz'
}
pets = [pet_1,pet_2,pet_3]
for pet in pets:
print(pet['宠物名']+'\t的主人是'+pet['主人'])
6-11 城市
cities = {
'上海':{
'人口':"非常多",
'国际地位':'非常高',
'所属国家':"中国"
},
'纽约':{
'人口':"非常多",
'国际地位':'非常高',
'所属国家':"美国"
},
'东京':{
'人口':"多",
'国际地位':'非常高',
'所属国家':"日本"
}
}
for city,city_info in cities.items():
if city == '东京':
all_cs = city+'是'+city_info['所属国家']+'的一个国际地位'+city_info['国际地位']+'!'+'人口也'+city_info['人口']+'大都市!,但是日本皇军不是人'
else:
all_cs = city+'是'+city_info['所属国家']+'的一个国际地位'+city_info['国际地位']+'!'+'人口也'+city_info['人口']+'大都市!'
print(all_cs)
第七章 用户输入和while循环
获取字符串输入input(),用户输入被获取以后,python将其存储在一个变量中供你使用
msg = input("输入点什么!")
print(msg)
sunlime text需从终端启动
1.1
prompet = '如果这句话超过一行的话那么就把他存储在这样一个变量中'
prompet +='\n这里是多行字符串的创建方式,可以这样拼接'
name = input(prompet)
print('这里是最后的效果: '+name+'!')#出于整洁大方等因素,适当添加空格换行
1.2使用int()来获取数值输入
age = input('你今年多大了?')
键入21 输出'21'
age = int(age)#将字符串'21'转化为数字21
age >= 18
输出True
1.3求模运算符(%)
将两个数相除并返回余数
number = input('请输入一个整数!')
if number%2 == 0:
print('这是一个偶数')
else:
print("这是一个奇数")
1.4在python2.7中获取输入
函数raw_in-put()来提示用户输入--->解读为字符串
此版本中input()函数将用户输入解读为python代码,并尝试运行他们
7-1汽车租凭
msg = input('你想要租什么车?')
print('你想要租的是: '+msg)
7-2餐馆订位
msg =input("你们有多少人?")
if msg > 8:
print("对不起,餐厅没有空桌了!")
else:
print("欢迎入座!")
7-3 10的整数倍
略
7.2while循环
for循环用于针对集合中的每个元素的一个代码块,而while循环不断地运行,直到指定的条件不满足为止
1.1使用while循环
number = 1
while number <= 5:
print(number)
number += 1
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)
2.4使用标签
在要求很多条件都满足才继续运行的程序中,可定义一个变量,用于判断整个程序是否处于活动状态。
这个变量被称为标志,充当了程序的交通信号灯。
程序在标志为True时继续运行,并在任何事件导致标志的值为False时让程序停止运行。
这样,在while语句中就只需检查一个条件——标志的当前值是否为True,
prompt = '\n输入quit退出此程序'
active =True
while active:
msg = input(prompt)
if msg == 'quit'
active =False
else:
print(msg)#原来是可以这么写的
2.4使用break退出循环
要立即退出循环,不在运行循环中余下的代码,也不考虑条件测试结果如何,可使用break语句。
break语句用于控制程序流程,可用它来控制那些代码执行,那些不执行
prompt = '\n输入quit退出程序'
while True:
city = input(prompt)
if city == 'quit':
break
else:
print('我喜欢去这个城市: '+city)
如果用户键入quit立即退出程序不拖拉
在任何Python循环中都可使用break语句。例如,可使用break语句来退出遍历列表或字典的for循环。
2.5在循环中使用continue
返回到程序循环开头,并根据条件测试结果决定是否继续循环
简单地说就是跳过这次循环,进入下一次循环
number = 0
while number < 10:
number+=1
if number % 2 == 0:
continue
print(number)
遇到 number%2==0时直接跳过此次循环直接忽略接下来的代码
打印奇数
2.6避免无限循环
每个while循环都必须有停止运行的途径,这样才不会没完没了的执行下去
x = 1
while x <= 5:
print(x)
这个循环将不会终止,若不小心编写这种程序直接按Crl+c结束这个进程
请确认程序至少有一个这样的出口供循环条件为False或让break得以执行
7-6三个出口
active = True
while active:
prompet = '请输入你的年龄查询你的票价!'
age = int(input(prompet))
if (age < 3) and (age > 0):
price = 0
elif (age >3) and (age <12):
price = 10
else:
price = 15
print('你好朋友你的票价是: '+str(price))
K = input("输入quit结束,输入其他继续")
if K == 'quit':
break
7.3使用while循环来处理列表和字典
到目前为止,我们每次都只处理了一项用户信息:获取用户的输入,再将输入打印出来或作出应答;
循环再次运行时,我们获悉另一个输入值并作出响应。
然而,要记录大量的用户和信息,需要在while循环中使用列表和字典。
for循环是一种遍历列表的有效方式,但在for循环中不应修改列表,否则将导致Python难以跟踪其中的元素。
要在遍历列表的同时对其进行修改,可使用while循环。
通过将while循环同列表和字典结合起来使用,可收集、存储并组织大量输入,供以后查看和显示。
3.1 在列表之间移动元素
假设有一个列表,其中包含新注册但未验证的网站用户,验证这些用户后如何将他们移入另一个已验证用户列表中呢
一种方法是使用while
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("\nThe following users have been confirmed:")
for confirmed_user in confirmed_users:
print(confirmed_user.title())
print(unconfirmed_users)#pop()永久删除
3.2删除包含特定值的所有列表元素
之前我们用函数remove()来删除列表中的特定值,但仅适用于列表中只出现了一次这个值
删除列表中所有包含特定值的元素使用while循环
pets = ['dog', 'cat', 'dog', 'goldfish', 'cat', 'rabbit', 'cat']
print(pets)
while 'cat' in pets:
pets.remove('cat')
print(pets)
不断删除'cat'直到这个值不在包含在列表中然后退出循环并再次打印列表
3.3使用用户输入来填充字典
可以使用while循环提示用户输入任意数量的信息,并将其存储在字典中
msg = {}#创建一个空字典
active = True #设置中继标志
while active:
name = input('你的名字叫啥')#输入姓名
love_singer = input('哪一位歌手是你的最爱')
msg[name] = love_singer
again = input('是否还有人想要参与调查?yes/no')
if again == 'no':
active = False
print('结果是:')
for name,lsinger in msg.items():
print(name+'最爱的歌手是: '+lsinger)
7-8 熟食店
sandwhich_orders = ['1','2','3']
finished_sandwhiches = []
while sandwhich_orders:
for sandwhich in sandwhich_orders:
print('正在制作你的三明治'+sandwhich)
finished_sandwhiches.append(sandwhich)
sandwhich_orders.remove(sandwhich)
print(finished_sandwhiches)
7-9 五香烟熏牛肉
sandwhich_orders = ['1','2','3','1','2','3','2','3','1','2','3','2','3','1','2','3']
print('2卖完了')
while '2' in sandwhich_orders:
sandwhich_orders.remove('2')
print(sandwhich_orders)
7-10 梦想的度假胜地
places = {}
go = []
while True:
name = input('你叫啥名字?')
while True:
place = input('你最想要去的地方?')
go.append(place)
continue_place = input('是否还有其他地方?yes/no')
if continue_place == 'no':
break
places[name] = go#存入字典
again = input('是否退出?yes/no')
if again == 'yes':
break
for name,place in places.items():
print(name+'最想去的地方是:\n')
print(place)
第八章 函数
函数是带名字的代码块,用于完成具体的工作。
8.1定义函数
def greet_user():
'''显示简单的问候语'''#❷处的文本是被称为文档字符串(docstring)的注释,描述了函数是做什么的。
#文档字符串用三引号括起,Python使用它们来生成有关程序中函数的文档。
print('hello')
greet_user()
1.1向函数传递信息
向函数括号内添加信息
def greet_user(username):
'''显示简单的问候语'''#❷处的文本是被称为文档字符串(docstring)的注释,描述了函数是做什么的。
#文档字符串用三引号括起,Python使用它们来生成有关程序中函数的文档。
print('hello'+user_name.title())
greet_user('rhz')#调用此函数,并向其中传递’rhz'这条信息
1.2实参和形参
在函数greet_user()的定义中,变量username是一个形参——函数完成其工作所需的一项信息。
在代码greet_user('jesse')中,值'jesse'是一个实参。实参是调用函数时传递给函数的信息。
我们调用函数时,将要让函数使用的信息放在括号内。
在greet_user('jesse')中,将实参'jesse'传递给了函数greet_user(),这个值被存储在形参username中。
8-1喜欢的图书
def favorite_book(title):
print('我最爱的图书是:'+title)
favorite_book('123')
2.传递实参
函数定义中可能不止一个形参,所以我们传递实参的时候使用位置实参,即是实参分别于形参的位置相对应
位置实参 一一对应
def singer(name,age):
print('歌手的名字叫做:'+name+'\n'+'歌手的年龄是:'+age)
singer('周杰伦','20')
关键字实参:每个实参都由变量名和值组成,还可使用列表和字典,传递给函数名称-值对。无需考虑位置,只需要对应传递就好
def singer(name,age):
print('歌手的名字叫做:'+name+'\n'+'歌手的年龄是:'+age)
singer(name='周杰伦',age='20')#向Python明确地指出了各个实参对应的形参。
关键字实参的顺序无关紧要,因为Python知道各个值该存储到哪个形参中。
2.3默认值
编写函数时,可给每个形参指定默认值
例如,如果你发现调用describe_pet()时,描述的大都是小狗,就可将形参animal_type的默认值设置为'dog'。
def ms_pet(name,animal_type='小狗'):
#默认值设定为小狗除非你重新给形参传递新的实参,这样将会忽略掉默认的参数
print('我的宠物:'+name+'的类型是:'+animal_type)
describe_pet(name='金毛')
describe_pet(name='金毛',animal_type='大狗')
若想直接使用位置实参,则务必把需要传递的形参放在不带有默认值的形参之前,位置参数的实参可以默认对应第一个形参
describe_pet('金毛')#自动对应第一个形参
即是使用默认值时,在形参列表中必须先列出没有默认值的形参,再列出有默认值的形参。
这让Python依然能够正确地解读位置实参。
2.4等效的函数调用
因为可以混合使用位置实参、关键字实参和默认值通常有多种等效的函数调用方式
def describe_pet(pet_name,pet_type = '狗'):
print('我的宠物:'+name+'的类型是:'+animal_type)
多种调用方式-一条名为小七的小狗和小八的仓鼠
describe_pet('小七')#位置实参
describe_pet(pet_name = '小七')#关键字实参,默认值为狗
describe_pet('小八','仓鼠')
describe_pet(pet_name='小八',pet_type = '仓鼠')
describe_pet(pet_type='仓鼠',pet_name = '小七')
自己选择最舒服的一种即可
2.5避免实参错误
'''
Traceback (most recent call last):
File "pets.py", line 6, in ❶
describe_pet() ❷
TypeError: describe_pet() missing 2 required positional arguments: 'animal_ ❸
type' and 'pet_name'
在❶处,traceback指出了问题出在什么地方,让我们能够回过头去找出函数调用中的错误。
在❷处,指出了导致问题的函数调用。在❸处,traceback指出该函数调用少两个实参,并指出了相应形参的名称。
如果这个函数存储在一个独立的文件中,我们也许无需打开这个文件并查看函数的代码,就能重新正确地编写函数调用。
'''
8.3 返回值
函数并非总是直接显示输出,它也可以处理一些数据然后返回一个或者一组的值,叫做返回值
在函数中可使用return语句将值返回到调用函数的代码行。
返回值让你能够将程序的大部分繁重工作移动到函数中去完成,从而简化程序
1.1返回简单值
def got_name(first_name,last_name):
full_name = first_name +' '+last_name
return full_name()
musician = got_name('久','石让')#定义一个变量musician用于存储返回的值
print(musician)
1.2让实参变成可选的
使用默认值让实参变成可选的
如有些人的名字会有前缀,如买买提-阿波罗,我们可以扩展函数处理提前名
def got_name(before_name,first_name,last_name):
full_name = before_name+'-'+first_name +' '+last_name
return full_name()
musician = got_name('买买提'+'久','石让')#定义一个变量musician用于存储返回的值
print(musician)
但并不是所有人都有提前名,
所以我们让提前名设置为可选的即是给实参before_name指定一个默认值空字符串并在用户没有提供提前名时不是用这个实参
#
def got_name(first_name,last_name,before_name=''):
#before_name=''注意带有默认值的可选的形参放末尾,方便后期直接位置调用
if before_name:
full_name = before_name+'-'+first_name +' '+last_name
else:
full_name = first_name +' '+last_name
return full_name()
musician = got_name('买买提'+'久','石让')#定义一个变量musician用于存储返回的值
print(musician)
musician = got_name('久','石让')#定义一个变量musician用于存储返回的值
print(musician)
3.返回字典
函数可返回任何类型的值
def build_person(first_name, last_name):
"""返回一个字典,其中包含有关一个人的信息"""
person = {'first': first_name, 'last': last_name}
return person
musician = build_person('jimi', 'hendrix')
print(musician)
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+"!")
我们添加了一条消息来告诉用户如何退出,然后在每次提示用户输入时,都检查他输入的是否是退出值,如果是,就退出循环。
现在,这个程序将不断地问候,直到用户输入的姓或名为'q'为止
8-6城市名
def city(name,country = '中国'):
city_1 = name+','+country
return city_1
city_2=city('重庆')
print(city_2)
专辑:
def make_album(name,a):
a =[]
while True:
b = input('请输入专辑名')
d = a.append(b)
print(b+'已经存储,输入q退出')
c = input('\n请输入:')
if c == 'q':
break
album = {name:a}
return album
albums=make_album('周杰伦','七度空间')
print(albums)
#
c_ablum = {names,a_1}
a =[]
def make_album(name,album_name):
namess = name
c_ablum[names]=namess
while True:
b = input('请输入专辑名')
a.append(b)
print(b+'已经存储,输入q退出')
c = input('\n请输入:')
if c == 'q':
break
c_ablum[a_1]=a
while True:
h=input('是否退出yes/no')
if h == 'yes':
break
e = input('请输入歌手名字:')
f = input('请输入专辑名字')
make_album(e,f)
8.4 传递列表
将列表传递给函数后,函数就能直接访问其内容。能提高效率
def greet_users(names):
'''想列表中的每位用户发起简单问候'''
for name in names:
msg= '你好'+name+'!'
print(msg)
usernames = ['热','周杰伦','米奇']
greet_users(usernames)
1.在函数中修改列表
将列表传递给函数后,函数就可对其进行修改。在函数中对这个列表所做的任何修改都是永久的,效率更高处理大量数据
为用户提交的设计制作3d打印模型的公司
un_designs = ['手机配件','耳机零件','芯片']#创建一个列表包含了未打印的设计
completed_models =[]
模拟打印每个设计,直到没有未打印的设计为止
打印每个设计后把他移动到列表completed_models中
while un_designs:
current_design = unprintes_designs.pop()
#模拟根据设计制作3d模型的过程
print('模型打印完成:'+current_design)
completed_models.append(current_design)
显示所打印好的所有模型
print('\n这些模型已经打印好了!')
for completed_model in completed_models:
print(completed_model)
重新组织代码,编写两个函数,每个函数具体做一件工作,效率更高
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("\nThe 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)
描述性的函数名让别人阅读这些代码时也能明白,虽然其中没有任何注释。
相比于没有使用函数的版本,这个程序更容易扩展和维护。
这个程序还演示了这样一种理念,即每个函数都应只负责一项具体的工作。
第一个函数打印每个设计,而第二个显示打印好的模型;这优于使用一个函数来完成两项工作。
编写函数时,如果你发现它执行的任务太多,请尝试将这些代码划分到两个函数中。
别忘了,总是可以在一个函数中调用另一个函数,这有助于将复杂的任务划分成一系列的步骤。
2.禁止函数修改列表
可向函数传递列表的副本来防止修改原列表
要将列表的副本传递给函数:
function_name(list_name[:])#使用切片的思维
print_models(unprinted_designs[:],completed_models)#在上一段程序中可以这样改
虽然向函数传递列表的副本可保留原始列表的内容,但没必要的时候不用这样操作,避免花时间和内存创建副本从而提高效率
8-10了不起的魔术师
magicman = ['大卫','刘谦','杰伦']
def show_magicians(names):
for name in names:
print('你好魔术师: '+name)
def make_great(names):
length =len(names)#获取列表长度
for a in range(length):#对列表中的元素进行处理
magicman[a]='the great '+magicman[a]#注意magicman[a]中的a只能是整型
show_magicians(magicman)#打印列表
make_great(magicman)#对列表中的每个元素进行修改
show_magicians(magicman)#确认列表变化
8-11 不变的魔术师(不修改原始列表,调用副本)
def make_great(names):
global fuben
length =len(names)#获取列表长度
fuben=[]
fuben = names[:]#创建副本
for a in range(length):#对列表中的元素进行处理
fuben[a]='the great '+fuben[a]#注意magicman[a]中的a只能是整型
magicman = ['大卫','刘谦','杰伦']
全局与局部https://editor.csdn.net/md/?articleId=122636049
或者:
def make_great(names):
length =len(names)#获取列表长度
fuben=[]
fuben = names[:]#创建副本
for a in range(length):#对列表中的元素进行处理
fuben[a]='the great '+fuben[a]
return fuben#注意magicman[a]中的a只能是整型
magicman = ['大卫','刘谦','杰伦']
fuben_1 = make_great(magicman)#需要一个变量来存储返回值,否则这个局部变量会消失
print(fuben_1)
8.5 传递任意数量的实参
有时候你不知道函数需要接受多少个实参,好在py允许函数从调用语句中收集任意数量的实参
列如,我们在接受订餐时永远无法预先知道顾客需要多少种配料
def make_pizza(*toppings):
'''打印顾客点的所有配料'''
print(toppings)
make_pizza('香菇')
make_pizza('火腿','鸡肉','芝士')
形参名topppings中的号让pthon创建一个名为toppings的空元组,并将收集到的所有值都存到这个元组中
注意,Python将实参封装到一个元组中,即便函数只收到一个值也如此:
输出:
('香菇',)
('火腿', '鸡肉', '芝士')
现在我们将这条print语句替换为一个循环,使他可以对配料列表进行遍历,对顾客点的披萨进行描述
def make_pizza(*toppings):
'''打印顾客点的所有配料'''
print('你的配料如下:')
for topping in toppings:
print('-'+topping)
make_pizza('香菇')
make_pizza('火腿','鸡肉','芝士')
8.5.1结合使用位置实参和任意数量实参
如果要让函数接受不同类型的实参,必须在函数定义中将接纳任意数量实参的形参放在最后。
Python先匹配位置实参和关键字实参,再将余下的实参都收集到最后一个形参中。
列如在前面的函数中加入一个描述顾客姓名的实参,必须将他的形参放在形参*toppings前面
def make_pizza(name,*toppings):
'''概述要制作的披萨'''
print(name+'的披萨配料是:')
for topping in toppings:
print('-'+topping)
make_pizza('rhz','香菇')
make_pizza('张三','火腿','鸡肉','芝士')
python将收到的第一个值存储在形参name中,并将其他的所有值存储在元组toppings中
8.5.2 使用任意数量的关键字实参
有时候,需要接受任意数量的实参,但预先不知道传递给函数的会是什么样的信息。
在这种情况下,可将函数编写成能够接受任意数量的键值对--调用语句提供了多少就接受多少
def bdild(first,last,**user_info):
'''创建一个字典,其中包含我们知道的有关用户的一切信息'''
profile= {}
profile['姓:'] = first
profile['名'] = last#把名和姓加入字典
for key,value in user_info.items():
profile[key] = value
#遍历字典user_info中的键值对,并将每个键值对都加入到字典profile中
return profile
#将字典profile返回给函数调用行
user_profile = build_profile('周', '杰伦',
地址='海外',
领域='音乐')
python中字典的键加引号的问题?--->https://www.zhihu.com/question/267315700
print(user_profile)
函数build_profile()的定义要求提供名和姓,同时允许用户根据需要提供任意数量的名称—值对。
形参**user_info中的两个星号让Python创建一个名为user_info的空字典,并将收到的所有名称—值对都封装到这个字典中。
#可以像访问其他字典那样访问user_info中的键值对
编写函数时,你可以以各种方式混合使用位置实参,关键字实参和任意数量的实参
8-12 三明治
def sandwhich_add(*toppings):
for a in toppings:
print('你添加的食材有:'+a)
sandwhich_add('火腿','鸡肉','芝士')
sandwhich_add('芝士')
8-13 用户简介
def bdild(first,last,**user_info):
'''创建一个字典,其中包含我们知道的有关用户的一切信息'''
profile= {}
profile['姓:'] = first
profile['名'] = last#把名和姓加入字典
for key,value in user_info.items():
profile[key] = value
#遍历字典user_info中的键值对,并将每个键值对都加入到字典profile中
return profile
#将字典profile返回给函数调用行
user_profile = bdild('r', 'hz',
地址='海外',
领域='无所不能')
print(user_profile)
关键字可用中文命名
8-14 汽车
def make_car(producer,size,**msg):
car_msg= {}
car_msg['制造商'] = producer
car_msg['汽车型号'] = size
for key,value in msg.items():
car_msg[key] = value
return car_msg
car = make_car('subaru', 'outback', color='blue', tow_package=True)
8.6将函数存储在模块中
函数的优点之一是使用它们可将代码块与主程序分离。
通过给函数指定描述性名称,可让主程序容易理解
更进一步,可以将函数存储在被称为模块的独立文件中,再将模块导入到主程序中。(import)语句导入模块中的代码
优点多比如隐藏程序代码细节,专注于程序高层逻辑,可在不同的程序中重用函数,与多人共享这个独立文件
1.导入整个模块
创建一个包含函数make_pizza()的模块,
pizz.py
def make_pizza(size, *toppings):
"""概述要制作的比萨"""
print("\nMaking a "+str(size)+
"-inch pizza with the following toppings:")
for topping in toppings:
print("- "+topping)
接下来我们在pizza.py所在目录中创建另一个名为makng_pizzas.py的文件
making_pizzas.py
import pizza#让python打开文件pizza.py,将其中的所有函数都复制到这个程序中,至此我们可在making_pizza里面使用pizza.py里的所有函数
pizza.make_pizza(16, 'pepperoni')
pizza.make_pizza(12, 'mushrooms', 'green peppers', 'extra cheese')
在此模块中调用另一个模块
调用被导入模块中的函数可使用模块名+.+函数名
2.导入特定的函数
语法
from module_name import function_name
通过逗号导入任意数量的函数
from module_name import function_0,function_1,function_2
如上面1的那个函数
from pizza import make_pizza
make_pizza(15,'牛肉')
make_pizza(13,'牛肉','芝士','白菜')
不难发现因为这种方式是明确的导入make_pizza()这个函数,所以使用函数时只需指定他的名称
3.使用as给函数指定别名
如果导入函数的名称可能与现有程序中函数的名称冲突,或者名称过长,可指定简短而独一无二的别名
如给make_pizza()指定别名(重命名):
from pizza import make_pizza as mp #from module_name import function_name as fn
mp(16, 'pepperoni')
mp(12, 'mushrooms', 'green peppers', 'extra cheese')
4.使用as给模块指定别名
语法
import module_name as mn
如上面的程序我们给模块pizza指定别名p
import pizza as p
p.make_pizza(16, 'pepperoni')
p.make_pizza(12, 'mushrooms', 'green peppers', 'extra cheese')
5.导入模块中的所有函数
使用星号’*‘,可让py导入模块中的所有函数,函数是明确的,所以可通过名称来直接调用函数
如果使用的是外来模块,最好确定模块中的函数名称是否与你自己的函数名称相冲突
from pizza import *
make_pizza(15,'牛肉')
make_pizza(13,'牛肉','芝士','白菜')
7.函数编写指南
1.给函数名称语义化,且仅包含小写字母和下划线
2.给每个函数都写上阐述其功能的注释---紧跟在函数定义后面并采用文档字符串格式
3.给形参指定默认值时,等号两边不要有空格
'''
def fuction_name(ps_1,ps_2,ps_3='default value')
'''
对于函数调用中的关键字实参,也应该这样做
fuction_name(ps_1,ps_2,ps_3='default value')
PEP 8(https://www.python.org/dev/peps/pep-0008/)
4.建议代码行的长度不要超过79字符,这样只要编辑器窗口适中,就能看到整行代码。
# 如果形参很多,导致函数定义的长度超过了79字符,可在函数定义中输入左括号后按回车键,并在下一行按两次Tab键,
# 从而将形参列表和只缩进一层的函数体区分开来。
5.如果程序或模块包含多个函数,可使用两个空行将相邻的函数分开,
# 这样将更容易知道前一个函数在什么地方结束,下一个函数从什么地方开始。
6.所有的import语句都应放在文件开头,唯一例外的情形是,在文件开头使用了注释来描述整个程序。
8-15 打印模型
printing_functions.py
import print_models as pm
pm.prints_1('苹果')
8-16 导入:
import module_name
from module_name import function_name
from module_name import function_name as fn
import module_name as mn
from module_name import *
TIP:
让实参变成可选值,提供实参,才能打印对应的形参
Python将非空字符串解读为True
第九章 类
#使用类创建对象时,每个对象都有面向对象的这种通用行为,可用来模拟现实情境
#根据类创建对象被称为实例化
#在python中首字母大写的名称指的是类
#1.创建和使用类
#1.1创建Dog类
#狗狗都具有的共同特征就是年龄和姓名,我们再赋予每条小狗sit()和roll_over这两项能力
##dog.py
class Dog():#定义一个名为Dog的类,这个类定义中的括号是空的,因为我们要从空白创建这个类
'''一次模拟小狗的简单尝试'''#文档字符串,对这个类的功能做了描述
def __init__(self,name,age):
'''初始化属性name和age'''
self.name = name
self.age = age
def sit(self):
'''模拟小狗被命令时蹲下'''
print(self.name.title()+'现在蹲下了!')
def roll_over(self):
'''模拟小狗被命令时打滚'''
print(self.name.title()+"翻滚了!")
#1.方法__init__()
#类中的函数被称为方法;
#Dog()类中的方法__init__()是一个特殊的方法
#每当你根据Dog类创建新实例时,Python都会自动运行它
#开头和末尾的两个下划线是一种约定,旨在区别默认方法与普通方法
#在这个定义中,形参self必不可少,且必须位于最前,python调用这个方法来创建dog实例时都自动传入实参self
#每个与类相关联的方法调用都自动传递实参self它是一个指向实例本身的引用,让实例能够访问类中的属性和方法
#因为这个方法默认,python每次都会自动调用,我们不需要传递参数给他,只需要给出self后的两个形参传递值就可
#以self为前缀的变量都可供类中所有方法使用
#self.name = name
#self.age = age
#我们还可以通过类的1任何实例来访问这些变量。
#self.name = name获 取存储在形参name中的值,并将其存储到变量name中,然后该变量被关联到当前创建的实例。
#self.age = age的作用与此类似。像这样可通过实例访问的变量称为属性。
#2.方法sit()和roll_over()
#由于这些方法不需要额外的信息如名字或年龄,所以他只有一个形参self
#后面将创建的实例能够访问这些方法,可以模拟小狗的打滚和蹲下,可以是小狗打滚的一段动画或是啥的。。。
2.python2.7中创建类
#在Python 2.7中创建类时,需要做细微的修改——在括号内包含单词object:
class ClassName(object):
--snip--
#这让Python 2.7类的行为更像Python 3类,从而简化了你的工作。
#在Python 2.7中定义Dog类时,代码类似于下面这样:
class Dog(object):
--snip--
9.1.2根据类创建实例
#可将类视为有关如何创建实例的说明。Dog类是一系列说明,让Python知道如何创建表示特定小狗的实例。
class Dog():
--snip--
my_dog = Dog('威廉',6)
print('我的狗狗名字叫:'+my_dog.name+'.')#❷
print('我的狗狗年龄是:'+str(my_dog.age)+'岁啦!')
#我们使用Dog类让python创建一条名为威廉的6岁狗狗
#1.pthon首先调用Dog类中的方法__init__()
#方法__init__()创建一个表示特定小狗的示例,并使用我们提供的值来设置属性name和age
#方法__init__()并未显式地包含return语句,但Python自动返回一个表示这条小狗的实例。
#我们将这个实例存储在变量my_dog中
#我们通常可认为首字母大写的名称指的是类,而小写的名称指的是根据类创建的实例
#1.访问属性
#使用句点表示法,❷处使用代码:my_dog.name来访问my_dog的属性name的值
#Python先找到实例my_dog,再查找与这个实例相关联的属性name
#在Dog类中引用这个属性时,使用的是self.name
#2.调用方法
class Dog():
--snip--
my_dog = Dog('willie', 6)
my_dog.sit()
#遇到代码my_dog.sit()时,python在类Dog中查找方法sit()并运行其中的代码
my_dog.roll_over()
#根据Dog类创建实例后,就可用句点表示法来调用Dog类中定义的任何方法
#3.创建多个实例
#可按需求根据类创建任意数量的实例
class Dog():
--snip--
my_dog = Dog('威廉',6)#每条小狗都是一个独立的实例,有自己的一组属性,能够执行相同的操作
your_dog = Dog('米奇',7)
print('我的狗狗:'+my_dog.name+'今年'+str(my_dog.age)+'岁啦!')
print('我的狗狗:'+your_dog.name+'今年'+str(your_dog.age)+'岁啦!')
my_dog.sit()
your_dog.sit()
9-1 餐馆
class Canguan():
def init(self,cg_name,cg_type):
self.name = cg_name
self.type = cg_type
def describe_cg(self):
print('我们的餐馆:'+self.name+'正在营业')
rest_cg = Canguan('巴费克','国际')
rest_cg.describe_cg()
print(rest_cg.name+rest_cg.type)
9-3用户:
class User():
def init(self,first_name,last_name,age,location):
self.fname = first_name
self.lname = last_name
self.age = age
self.dz = location
def ms_user(self):
print('您好 '+self.fname +'先生!')
print('您的地址是:'+self.dz)
print('你今年的岁数是:'+self.age)
def greet_user(self):
fullname = self.fname+self.lname
print('你好:'+fullname+'先生!')
user_1 = User('周','杰伦','33','中国台湾省')
user_1.ms_user()
user_1.greet_user()
9.2 使用类和实例
#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())
2.2给属性指定默认值
# 类中的每个属性都必须有初始值
# 在某些情况下可在方法__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):
--snip--
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()
#实际呢,里程表读数为0的汽车并不多,因此我们要一个修改该属性的值的途径
2.3修改属性的值
#1.直接修改属性的值
#通过实例则直接访问它然后修改
class Car():
--snip--
my_new_car = Car('奥迪','a4','2016')
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('奥迪','a4','2016')
my_new_car.update_odometer(23)# ❷
my_new_car.read_odometer()
#方法update_odometer()还可进行扩展,让他在修改里程表读数的同时禁止任何人把读数往回调:
class Car():
--snip--
def update_odometer(self, mileage):
"""
将里程表读数设置为指定的值
禁止将里程表读数往回调
"""
if mileage >= self.odometer_reading:
self.odometer_reading = mileage
else:
print('你不能往回调这个值')
#3.通过方法对属性的值进行递增
def increment_odometer(self, miles): #❶
"""将里程表读数增加指定的量"""
if miles > 0:
self.odometer_reading+= miles
else:
print('里程数不能为负值!')
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()
9-4 就餐人数:
class User():
def init(self,first_name,last_name,age,location):
self.fname = first_name
self.lname = last_name
self.age = age
self.dz = location
self.login_attempts = 0
def increment_login_attempts(self):
self.login_attempts +=1
def reset_login_attempts(self):
self.login_attempts = 0
def ms_user(self):
print('您好 '+self.fname +'先生!')
print('您的地址是:'+self.dz)
print('你今年的岁数是:'+self.age)
def greet_user(self):
fullname = self.fname+self.lname
print('你好:'+fullname+'先生!')
user_1 = User('周','杰伦','33','中国台湾省')
user_1.increment_login_attempts()
user_1.increment_login_attempts()
print(str(user_1.login_attempts))
user_1.reset_login_attempts()
print(str(user_1.login_attempts))
9.3继承
#编写类时可以继承已经编写的现成的类,这时使用继承。获得所有属性和方法
#原有的类称为父类;新类称为子类;
#新类也可以定义自己的属性和方法
1.1子类的方法init()
#创建子类的实例前,Py先要给父类的所有属性赋值。子类的方法__init__()需要父类施以援手
#创建一个基于父类Car的电动车
#eletric_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
class ElectricCar(Car):#定义子类时把父类的名称放在括号里
'''电动汽车的相比于Car类的独特之处'''
def ___init__(self,make,model,year):#方法__init__()接受创建Car实例所需的信息
'''初始化父类的属性'''
super().__init__(make,model,year)
#super()一个让父类和子类关联起来的特殊函数
#这行代码让Py调用Elec-triCar的父类的方法__init__(),让子类实例包含父类的所有属性
#父类也称为超类(superclass),名称super因此而得名
my_tesla = ElectricCar('tesla', 'model s', 2016) #测试继承是否发挥作用而创建一辆电动汽车提供的信息与创建普通汽车时相同
#创建电动车并将其存储在变量my_tesla中
#调用ElectricCar类中定义的方法__init__(),后者让py调用父类Car中定义的方法__init__()
#除方法__init__()外,电动汽车没有其他特有的属性和方法。
print(my_tesla.get_descriptive_name())
#ElectricCar实例的行为与Car实例一样,现在可以开始定义电动汽车特有的属性和方法了。
2.py2.7中的继承语法与3.不同
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。
3.给子类定义属性和方法
#让一个类继承另一个类后,可添加-区分-子类和父类所需要的新属性和方法
#如我们来给电动车添加电瓶属性
class Car():
--snip--
class ElectricCar(Car):
'''给它加上特有属性电瓶首先初始化父类的属性,做个链接'''
def __init__(self,make,model,year):#接受创建Car类所需的信息
'''开始初始化父类属性'''
super().__init__(make,model,year)
'''初始化电动汽车特有的属性'''
self.batter_size = 70
#我们添加了新属性self.battery_size并设置默认值为70
#根据ElectricCar类创建的所有实例都将包含这个属性,但所有Car实例都不包含它。
def describe_battery(self):# ❷
"""打印一条描述电瓶容量的消息"""
print("这辆车有 "+str(self.battery_size)+"-kWh 的电量.")
my_tesla = ElectricCar('tesla', 'model s', 2016)
print(my_tesla.get_descriptive_name())
my_tesla.describe_battery()
4.重写父类的方法
#对于父类的方法,只要它不符合子类模拟的实物的行为,都可对其进行重写。
# 为此,可在子类中定义一个这样的方法,即它与要重写的父类方法同名。
# 这样,Python将不会考虑这个父类方法,而只关注你在子类中定义的相应方法。
'''
假设Car类有一个名为fill_gas_tank()的方法,它对全电动汽车来说毫无意义,因此你可能想重写它。
下面演示了一种重写方式:
'''
class ElectricCar(Car):
--snip--
def fill_gas_tank():
"""电动汽车没有油箱"""
print("This car doesn't need a gas tank!")
'''
现在,如果有人对电动汽车调用方法fill_gas_tank()
,Python将忽略Car类中的方法fill_gas_tank(),转而运行上述代码。
使用继承时,可让子类保留从父类那里继承而来的精华,并剔除不需要的糟粕。
'''
5.将实例用作属性
#用代码模拟实物时可能会发现自己对类添加的细节越来越多:
#属性和方法清单以及文件都越来越长在这种情况下可能需要将类的一部分作为一个独立的类提取出来
#即将大型类拆分为多个协同工作的小类
'''
例如,不断给ElectricCar类添加细节时,
我们可能会发现其中包含很多专门针对汽车电瓶的属性和方法。
在这种情况下,我们可将这些属性和方法提取出来,放到另一个名
为Battery的类中,并将一个Battery实例用作ElectricCar类的一个属性:
'''
class Car():
--snip--
class Battery(): ❶定义一个新类且没有继承任何类
"""一次模拟电动汽车电瓶的简单尝试"""
def __init__(self, battery_size=70):
❷方法__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:
my_tesla.battery.describe_battery()
#这看似做了很多额外的工作,但现在我们想多详细地描述电瓶都可以,且不会导致ElectricCar类混乱不堪。
#在ElectricCar类中,我们添加了一个名为self.battery的属性(见❹)。
# 这行代码让Python创建一个新的Battery实例(由于没有指定尺寸,因此为默认值70),
# 并将该实例存储在属性self.battery中。每当方法__init__()被调用时,
# 都将执行该操作;因此现在每个ElectricCar实例都包含一个自动创建的Battery实例。
'''我的理解
1.你用类创建了一个实例
2.你要把自己提供的信息交给类处理,但是世界那么大怎么防止误入花花世界呢?
3.self标识帮助你找到正确的地方,然后后面跟上形参你赋值交信息给他自动处理
4.你创建了个电瓶车的类,你确不知道他的电池是几号,难道你每次创建电瓶车都要再去写一大串代码问问咱的电瓶车几号电池?咋就是说不用呀,直接给所有型号的电池找个家,创建一个电池类不就得了
5.如果说单独创建个电池类你嫌每次都要单独再去给电瓶车创建电池类再访问里面的属性和方法太麻烦,你直接把他当作电瓶车的属性不就得了,每次只要通过类创建实例,self当作你的路标,句号表示法当作你们的交流工具,你只管疯狂赋值不就o了?
class Battery():
def __init__(self,battery_size):
self.size = battery_size
def dcxh(self):
print('俺是'+self.size+'型号的老铁!')
dc_1 = Battery('大号')
print(dc_1.dcxh())
dc_1 = ElectricCar('中国', '兰博基尼', 1200)
dc_1.get_descriptive_name()
#用作电瓶的属性
class ElectricCar(Car):
"""电动汽车的独特之处"""
def __init__(self, make, model, year):
"""
初始化父类的属性,再初始化电动汽车特有的属性
"""
super().__init__(make, model, year)
self.battery = Battery()
--snip--
dc_1 = ElectricCar('中国','兰博基尼',‘1200’)
dc_1.battery.dcxh()
dc_1.get_descriptive_name()
如果只是创建电池类的话我要调用这些东西,还要反复的创建类,用作属性的话只需要创建一次类,就可通过句号访问属性来调用电池类里面的方法了,如果实例不用作属性,一次创建可能不算什么,但是批量的话就严重的浪费资源,而且后期维护也比较累
'''
6.模拟实物
#模拟较复杂的物件(如电动汽车)时,需要解决一些有趣的问题。续航里程是电瓶的属性还是汽车的属性呢?
#我们也可以这样做:将方法get_range()还留在Battery类中,
#但向它传递一个参数,如car_model;在这种情况下,方法get_range()将根据电瓶容量和汽车型号报告续航里程。
#这让你进入了程序员的另一个境界:解决上述问题时,你从较高的逻辑层面(而不是语法层面)考虑;
# 你考虑的不是Python,而是如何使用代码来表示实物。
# 到达这种境界后,你经常会发现,现实世界的建模方法并没有对错之分。
# 有些方法的效率更高,但要找出效率最高的表示法,需要经过一定的实践。只要代码像你希望的那样运行,就说明你做得很好!
# 即便你发现自己不得不多次尝试使用不同的方法来重写类,也不必气馁;要编写出高效、准确的代码,都得经过这样的过程。
9-6 冰淇淋小店
class Canguan():
def init(self,cg_name,cg_type):
self.name = cg_name
self.type = cg_type
def describe_cg(self):
print('我们的餐馆:'+self.name+'正在营业')
class IceCreamStand(Canguan):
def init(self,cg_name,cg_type):
super().init(cg_name,cg_type)
self.flavors = ['草莓','芒果']
def icecream(self):
for icecream_1 in self.flavors:
print('你点哪个?我们有如下口味冰淇淋:')
print(icecream_1)
print(self.flavors)
ice = IceCreamStand('巴费克','国际')
ice.describe_cg()
print(ice.name+ice.type)
ice.icecream()
print('\n')
print(ice.flavors)
'''
我们的餐馆:巴费克正在营业
巴费克国际
你点哪个?我们有如下口味冰淇淋:
草莓
你点哪个?我们有如下口味冰淇淋:
芒果
['草莓', '芒果']
['草莓', '芒果']
'''
9-7管理员
class User():
def init(self,first_name,last_name,age,location):
self.fname = first_name
self.lname = last_name
self.age = age
self.dz = location
def ms_user(self):
print('您好 '+self.fname +'先生!')
print('您的地址是:'+self.dz)
print('你今年的岁数是:'+self.age)
def greet_user(self):
fullname = self.fname+self.lname
print('你好:'+fullname+'先生!')
class Admin(User):
def init(self,first_name,last_name,age,location):
super().init(first_name,last_name,age,location)
self.privileges = ['can add post',"can delete post","can ban user"]
def show_qx(self):
print('管理员admin的权限是:')
print(self.privileges)
9-8权限
class User():
def init(self,first_name,last_name,age,location):
self.fname = first_name
self.lname = last_name
self.age = age
self.dz = location
def ms_user(self):
print('您好 '+self.fname +'先生!')
print('您的地址是:'+self.dz)
print('你今年的岁数是:'+str(self.age))
def greet_user(self):
fullname = self.fname+self.lname
print('你好:'+fullname+'先生!')
class Admin(User):
def init(self,first_name,last_name,age=30,location='中国'):
super().init(first_name,last_name,age,location)
self.qx=Privileges()
#self.privileges = ['can add post',"can delete post","can ban user"]
#def show_qx(self):
#print('管理员admin的权限是:')
#print(self.privileges)
class Privileges():
def init(self):
self.privileges = ['can add post',"can delete post","can ban user"]
def show_qx(self):
print('管理员admin的权限是:')
print(self.privileges)
admin_1 = Admin('周','杰伦')
admin_1.qx.show_qx()
admin_1.ms_user()
admin_1.greet_user()
9-9电瓶升级:
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=70):
#❷方法init()除self外,还有另一个形参battery_size。
#这个形参是可选的:如果没有给它提供值,电瓶容量将被设置为70。
"""初始化电瓶的属性"""
self.battery = battery
def describe_battery(self): #❸
"""打印一条描述电瓶容量的消息"""
print("This car has a "+str(self.battery)+"-kWh battery.")
def upgrade_battery(self):
if self.battery != 85:
self.battery = 85
class ElectricCar(Car):
"""电动汽车的独特之处"""
def init(self, make, model, year):
"""
初始化父类的属性,再初始化电动汽车特有的属性
"""
super().init(make, model, year)
self.battery = Battery()
car_1 = ElectricCar('中国制造','奥迪','2015')
car_1.battery.describe_battery()
car_1.battery.upgrade_battery()
car_1.battery.describe_battery()
9.4导入类
#Python允许你将类存储在模块中,然后在主程序中导入所需的模块。
#1.导入单个类
#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
#接下来创建另一个文件my_car.py,我们在其中导入Car类并创建其实例
from car import Car#让p打开模块car并导入其中的Car类
my_new_car = Car('奥迪','a4','2015')
print(my_new_car.get_descriptive_name())
my_new_car.odometer_reading = 23
my_new_car.read_odometer()
#导入类是一种有效的编程方式,通过将这个类移到一个模块中,并导入该模块,,你将可以使用这个模块内的所有内容
#大大简化了代码,让你的精力集中在更高层次的逻辑上面
2.在一个模块中存储多个类
#虽说同一个模块中的类之间应该具有某种关联性,但你也可根据需要在一个模块中存储任意数量的类
#如将电池类和电动汽车类加入到模块car.py中
#car.py
class Car():
--snip--
class Battery():
--snip--
class ElectricCar(Car):
"""模拟电动汽车的独特之处"""
--snip--
#现在我们尝试新建一个py文件并导入我们刚刚创建的模块
#my_electric_car.py
from car import ElectricCar
my_tesla = ElectricCar('tesla', 'model s', 2016)
print(my_tesla.get_descriptive_name())
my_tesla.battery.describe_battery()
my_tesla.battery.get_range()
#3.从一个模块中导入多个类
#将Car和ElectriCar类都导入:
#从一个模块中导入多个类时,用逗号分隔了各个类
#my_cars.py
from car import Car,ElectricCar
my_beetle = Car('volkswagen', 'beetle', 2016) #创建一辆大众普通甲壳汽车
print(my_beetle.get_descriptive_name())
my_tesla = ElectricCar('tesla', 'roadster', 2016) #创建一辆特斯拉电动汽车
print(my_tesla.get_descriptive_name())
#4.导入整个模块
#你还可以导入整个模块,再使用句点表示法访问需要的类。
#由于创建类实例的代码都包含模块名,因此不会与当前文件使用的任何名称发生冲突
#my_cars.py---->创建一辆普通汽车和一辆电动汽车
import car
my_car = car.Car('兰博基尼','中国制作','2030')
print(my_car.get_descriptive_name)
my_car =car.ElectricCar('特斯拉','国外制作','2031')
print(my_car.get_descriptive_name)
#5.导入模块中的所有类
from module_name import *
#这种导入方式不被推荐:
#1.不能直观的展示你想使用的模块中的类
#2.可能会与程序文件中的其他类同名,而出现错误
#3.需要从一个模块中导入很多类时,最好导入整个模块,并使用module_name.class_name语法来访问类
#虽然这样也没有在开头列出用到的所有类,但你也清楚的知道了在程序的哪些地方使用了导入的模块
#也避免了可能的名称冲突
#6.在一个模块中导入另一个模块
#有时候需要将类分散到多个模块中,避免多种情况比如说对不同模块所储存类的大致分类
#若把这些不同的类存储在多个模块中时,我们可能发现有些模块需要依存另一个模块里的类此时我们可在前一个模块中导入必要的类
#例如,下面将Car类存储在一个模块中,并将ElectricCar和Battery类存储在另一个模块中。
# 我们将第二个模块命名为electric_car.py并将Battery和ElectricCar类复制到这个模块中:
#electric_car.py
"""一组可用于表示电动汽车的类"""
from car import Car# 1
class Battery():
--snip--
class ElectricCar(Car):
--snip--
#ElectricCar类需要访问其父类Car,因此在1处,我们直接将Car类导入该模块中
#现在可以分别从每个模块中导入类,以根据需要创建任何类型的汽车了:
#my_cars.py
from car import Car# ❶
from electric_car import ElectricCar
my_beetle = Car('volkswagen', 'beetle', 2016)
print(my_beetle.get_descriptive_name())
my_tesla = ElectricCar('tesla', 'roadster', 2016)
print(my_tesla.get_descriptive_name())
#7.自定义工作流程
#在组织大型项目的代码方面,py提供了很多选项,熟悉这些选项很重要
#你能确定那种项目组织方式是最佳的
#并能理解别人开发的项目
'''
一开始应让代码结构尽可能简单。先尽可能在一个文件中完成所有的工作,
确定一切都能正确运行后,再将类移到独立的模块中。如果你喜欢模块和文件的交互方式,可在项目开始时就尝试将
类存储到模块中。先找出让你能够编写出可行代码的方式,再尝试让代码更为组织有序。
'''
9-10导入Restaurant类:
#test_1.py---->将最新的餐馆类存储在其中
class Canguan():
def __init__(self,cg_name,cg_type):
self.name = cg_name
self.type = cg_type
def describe_cg(self):
print('我们的餐馆:'+self.name+'正在营业')
#test_2.py---->在这个文件中导入餐馆类并创建一个餐馆实例后调用餐馆的一个方法
from test_1 import Canguan
cg_1 = Canguan('米其林','西餐厅')
cg_1.describe_cg()
9-11导入Admin类
#省去操作将User、Privileges和Admin类存储在一个模块admin_1.py中
#admin_2.py
import admin_1
admin_Rhz = admin_1.Admin('r','hz')
admin_Rhz.admin_1.show_privileges()
9-12 多个模块
#省去操作将User类存储在模块user_User.py中
#user_User.py
class User()
--snip--
#省去操作将Privileges和Admin类存储在模块user_PA.py中
#user_PA.py
from user_User import User#将User类导入
class Admin(User)
--snip--
class Privileges()
#admin_3.py
from user_User import User
from user_PA import Privileges,Admin
user_rhz = User('rhz','20','重庆')
user_rhz.show_privileges()
9.5Python标准库
#py标准库是一组模块,安装的Py都包含他
#即是其他程序员已经写好的模块
#只需import下就可使用标准库中的任何函数和类
#下面来看模块collections中的一个类——OrderedDict。
#此类可记录键值对的添加顺序:
#favorite_languages.py
from collections import OrderedDict #❶从模块collections中导入了OrderedDict类
favorite_languages = OrderedDict()# ❷#创建了orderedDict类的一个实例并将其存储到f_l中,直接调用创建一个空的有序字典没花括号
favorite_languages['jen'] = 'python' #❸以每次一对的方式添加名字-语言对
favorite_languages['sarah'] = 'c'
favorite_languages['edward'] = 'ruby'
favorite_languages['phil'] = 'python'
for name, language in favorite_languages.items():# ❹遍历f_L
print(name.title()+"'s favorite language is "+
language.title()+".")
#这个类兼具列表和字典的主要优点(在将信息关联起来的同时保留原来的顺序)
#py3.7以上默认排序
9-14 骰子
from random import randint
class Die():
def init(self,sides = 6,tz_cs = 1 ):
self.sides = sides
self.cs = tz_cs
def roll_die(self,tz_cs):
#返回一个1,y的随机数
a = []
for i in range(0,tz_cs):
x = randint(1,self.sides)
a.append(x)
print(a)
tz_6 = Die(6)
tz_6.roll_die(10)
9-15Python标准库:
#访问http://pymotw.com/并查看其
9.6类编码风格
#类名应采用驼峰命名法-->
# 将类名中的每个单词的首字母都大写,而不使用下划线。
#实例名和模块名都采用小写格式,并在单词之间加上下划线
#对于每个类,都应紧跟在类定义后面包含一个文档字符串
#简要的描述类的功能,并遵循编写函数的文档字符串时采用的格式约定
#每个模块也都应包含一个文档字符串,对其中的类用途进行描述
#可使用空行来组织代码,但不可滥用
#在类中,可使用一个空行来分隔方法
#在模块中,可用两个空行来分隔类
#需要同时导入标准库中的模块和你编写的模块时
# 先编写导入标准库模块的import语句
# 再添加一个空行,然后编写导入你自己编写的模块的import语句
#因为包含多条导入语句时这样做更清晰明了
第十章 文件和异常
#本章学习的技能可提高程序的适用性、可用性和稳定性。
#1.从文件中读取数据---->到内存中后期才可获取这些数据两种办法逐行或一次性读取
'''第一种一次性读取'''
#1.1一次性读取整个文件
#创建一个包含几行文本的文件
#pi_digits.txt-文-档-内-容---->3.1415926535
#8979323846
#2643383279
#下面使用程序打开并读取这个文件,再将其内容打印
#file_reader.py
with open('pi_digits.txt') as file_object:
contents = file_object.read()
print(contents)
#open('要打开的文件的名称')----->py在当前目录中查找指定的文件
#函数open('pi_digits.txt')返回一个表示文件pi_digits.txt的对象
#py将这个对象存储在变量中
#关键字with在不再需要访问文件后将其关闭
#当然也可使用open()和close()来打开和关闭,但这样做难免程序出现Bug无法运行close()语句以至于文件不会关闭
#后造成数据没有保存
#且也不知道close()语句准确安放的位置,提前或错失关闭文件的时机
#使用with让python自己去判断时机把
#方法read()读取文件的全部内容,并将其作为一个长长的字符串存储在变量contents中
#只要打印contents的值即可打印问嗯的全部内容
#read()到达文件末尾会自动返回一个空字符串,所以打印时末尾会多一个空行
#去除输出时的末尾空行---》
print(contents.rstrip())
#1.2文件路径
#提供具体文件路径,让python到系统特定的位置去查找文件
#1.若此文件位于同一目录不同文件夹中,使用相对文件路径:
#1.1 Linux和os x:
with open ('text_files/filename.txt') as file_object:
#1.2 windows:
with open ('text_files\filename.txt') as file_object:
'''反斜杠'\'和斜杠'/'的区别'''
#2,绝对文件路径:
# 绝对路径通常比相对路径更长,因此将其存储在一个变量中,再将该变量传递给open()会有所帮助。
#2.1 Linux和os x:
file_path = '/home/ehmatthes/other_files/text_files/filename.txt'
with open(file_path) as file_object:
#2,2 win:
file_path = 'C:\Users\ehmatthes\other_files\text_files\filename.txt'
with open(file_path) as file_object:
'''
另外,由于反斜杠在Python中被视为转义标记,为在Windows中确保万无一失,
应以原始字符串的方式指定路径,即在开头的单引号前加上r。
file_path = r'C:\Users\ehmatthes\other_files\text_files\filename.txt'
'''
'''第二钟逐行读取'''
#2.逐行读取
#你可能要遍历一个包含天气数据的文件,并使用天气描述中包含字样sunny的行
#要以每次一行的方式检查文件,可对文件对象使用for循环
#file_reader.py
filename = 'pi_digits.txt'#将要读取的文件的名词存储在变量filename中,变量filename并非一个实际的文件
with open(filename) as file_object:#掉用open()后,将一个表示文件及其内容的对象存储到了变量file_object中
for line in file_object:
print(line)
#打印时会发现空白行增多了,每行末尾本身有个换行符,print语句也会加上一个换行符,共两个换行符
#即是一个来自文件,一个来自Print
#在print中line.rstrip()即可去除
#3.创建一个包含文件各行内容的列表
#使用关键字with时,open()返回的对象只在with代码块内可用,如果需要在with代码块外访问文件的内容:
#可在with代码块内将文件的各行存储在一个列表中,并在with代码块外使用该列表(即是使用该文件内容)
#例子:
filename = 'rhz.txt'
with open(filename) as file_object:
lines = file_object.readlines()
#readlines()方法从文件中读取每一行,并将其存储在一个列表中;
#然后该列表被存储到变量lines中;在with代码块外,我们依然可以使用for循环来打印Lines中的各行
#列表lines中的每个元素都对应文件中的每一行
for line in lines:
print(line.rstrip())
#4.使用文件的内容
#将文件读取到内存后,就可以用任何方式使用这些数据了。
#接下来以简单的方式使用圆周率的值
#pi_string.py
filename = 'rhz.txt'#打开目标文件
with open(filename) as file_object:
lines = file_object.readlines()#将文件中的所有行存进列表
pi_string = ''#创建变量用于存放存储的值
for line in lines:#使用for循环将各行都加入pi_string,并删除末尾的换行符
pi_string+=line.rstrip()
print(pi_string)#打印这个字符串和它的长度
print(len(pi_string))
'''输出
3.1415926535 8979323846 2643383279
36
'''
#在变量pi_string存储的字符串中,包含原来位于每行左边的空格,为了删除他们可使用strip()替换rstrip()
pi_string+=line.strip()
'''输出
3.141592653589793238462643383279
32
PS:
读取文本文件时,Python将其中的所有文本都解读为字符串。如果你读取的是数字
,并要将其作为数值使用,就必须使用函数int()将其转换为整数,或使用函数float()将其转换为浮点数。
'''
#5.包含一百万位的大型文件
#上面的代码同样可处理包含PI的百万位的小数,同样的代码就行
#在这里我们只打印到小数点后50位,以免终端显示全部100w位而不断翻滚
#pi_string.py
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))
#6.圆周率值中包含你的生日吗
#接下来编写一个程序确定某个人的生日是否包含在圆周率值的前百万位中
#可将生日表示为一个由数字组成的字符串,在检查这个字符串是否包含在pi_string中
filename = 'pi_millio_digits.txt'
with open(filename) as file_object:
lines = file_object.readlines()
pi_string=''
for line in lines:
pi_string+=line.strip()
birthday = input('输入你的生日:')
if birthday in pi_string:
print('你的生日出现在pi中了')
else:
print('你的生日没有出现在百万位中')
10-1 python学习笔记
filename = r'C:\Users\86178\Desktop\py复习\python.txt'
第一次打印时读取整个文件的内容
with open(filename, encoding='utf-8') as file_object:
contents = file_object.read() # 读取文件所有内容并存储到变量中,末尾带有空行
print(contents)
第一次好了
第二次打印时遍历文件对象
with open(filename, encoding='utf-8') as file_object: # 掉用open()后,将一个表示文件及其内容的对象存储到了变量file_object中
for line in file_object:
print(line)
print('第二次好了')
第三次打印时将各行存储在一个列表中,再在with代码块外打印它们。
with open(filename, encoding='utf-8') as pybj:
lines = pybj.readlines() # 每行提取后装进列表中
pi_string = ''
print(lines)
print(pi_string)
print('第三次1')
for line in lines:
pi_string += line.strip() # 消除列表每行尾的空行
print(lines)
print(pi_string)
print('第三次2')
10-2 c语言学习笔记
#使用方法replace()将字符串中的特定单词都替换为另一个单词
msg = '我喜欢狗狗'
msssg = msg.replace('狗','猫')
print(msssg)
#replace ()方法不能永久性的将字符串中的字符替换。它的替换效果是暂时的。
filename = r'C:\Users\86178\Desktop\py复习\python.txt'
# 第一次打印时读取整个文件的内容
with open(filename, encoding='utf-8') as pybj:
lines = pybj.readlines()
pi_string = ''
for line in lines:
pi_string += line.replace('python', 'c').strip() # 消除列表每行尾的空行
print(lines)
print(pi_string)
print('第三次2')
10.2写入文件
#保存数据的最简单的方式之一是将其写入到文件中。
2.1写入空文件
#要将文本写入文件,你在调用open()时需要提供另一个实参,告诉py你要写入打开的文件。
#write_message.py
filename = 'programing.txt'
with open(filename,'w')as file_object:
#第一个实参是要打开的文件的名称
#第二个实参'w'告诉py,我们要以写入模式打开这个文件
#python默认只读模式打开文件,可给模式实参赋值
#模式实参---》读取模式('r'),写入模式('w'),附加模式('a'),或者可读取且写入文件的模式('r+')
file_object.write('我爱程序')
#write()方法将一个字符串写入文件。
#Python只能将字符串写入文本文件。要将数值数据存储到文本文件中,必须先使用函数str()将其转换为字符串格式。
#如果你要写入的文件不存在,函数open()将自动创建它
#以写入(‘w')模式打开文件时千万要小心,因为如果指定文件已经存在,py将在返回文件对象前清空该文件
2.2写入多行
#函数write()不会在你写入的文本末尾添加换行符,所以若写入多行时没有指定换行符,文件看起来不怎么美观
I love programming.I love creating new games.
#可手动写入换行符实现换行
filename = 'kongbai.txt'
with open(filename,'w')as file_object:
file_object.write('我爱程序\n')#手动写入换行符
file_object.write('第二行文字\n')
#输出:
I love programming.
I love creating new games.
2.3附加到文件
#如果你要给文件添加内容,而不是覆盖原有的内容,请以附加模式打开文件
#以附加模式打开文件时,py不会在返回文件对象前清空文件,而你写入到文件的行都将添加到文件末尾。
#如果指定的文件不存在,py将自动创建一个空文件
#write_msg.py
filename = 'rhz.txt'#假设rhz.txt已经存在且里面有文本内容
with open(filename,'a')as file_object:
file_object.write('我也喜欢在数据中\n')
#最终的结果是,文件原来的内容还在,他们后面是我们刚刚添加的内容
10-3 访客:
filename = 'guest.txt'
c = []
while True:
a = input('请输入你的名字!')
c.append(a)
b = input('退出还是不退出,yes/no')
if b == 'yes':
break
with open(filename, 'w')as user:
for i in c:
user.write(i + '-')
guestname = ''
with open(filename, 'r')as user_get:
lines = user_get.readlines()
for line in lines:
guestname += line.strip()
print(guestname)
10-4 访客名单
filename = 'guest_book.txt'
c = []
e = 0
while True:
with open(filename,'a')as gfw:
a = input('请输入你的名字!')
c.append(a)
if a == '':
print('请输入你的正确用户名')
else:
print('欢迎您!'+a.title())
# for i in c:
# if i == a:
# e+=1
# if e>1:
# gfw.replace(e-1,e)
# else:
gfw.write(a.title()+'今天访问过本系统\n')
b = input('退出还是不退出,yes/no')
if b == 'yes':
break
10.3 异常
#py使用被称为异常的特殊对象来管理程序执行期间发生的错误
#每当出现异常时py自动创建一个异常对象,通过编写处理该异常的代码,程序将继续运行
#如果你未对异常进行处理,程序将停止,并显示一个traceback,其中包含异常报告
#使用tr-except代码块处理异常
#即是当出现错误时显示你编写的有好的错误信息而不是错误回馈
#3.1处理ZeroDivisionError异常
#print(5/0)
#这种情况下python无法处理5/0的情况,所以py终止这个程序,并指出引发了哪种异常
# 下面我们将告诉py如何处理这种错误:
#使用try-except异常
#当你认为可能会出现错误时可使用此代码块来处理,让p尝试运行一些代码,并告诉它如果这些代码引发了指定的异常,该怎么办
try:
print(5/0)
except ZeroDivisionError:
print('你不能除以一个0')
'''如果try代码块中的代码运行起来没问题py将跳过except代码块
如果try代码块中的代码导致了错误,Py将查找这样的except代码块并运行其中的代码
except的指定的错误与发生的一致为前提
且程序将继续运行try...后其余的代码
'''
#3.3使用异常避免崩溃
#避免崩溃可让程序就算遇到错误也能妥善的处理错误是程序不至于崩溃
#division.py
print('给我两个数字,让后我会让他们相除')
print('输入q退出')
while True:
first_number = input('\nFirst number:')
if first_number == 'q':
break
second_number == input('第二个数字')
if second_number == 'q':
break
answer = int(first_number) / int(second_number)
print(answer)
#这个程序没有采取处理错误的措施,所以当除数为0时程序会崩溃,在3,4我们尝试解决
#3.4 else代码块
#try-except代码块还包含一个else代码块,依赖于try代码块成功执行的代码都应放到else代码块中
while True:
first_number = input("\nFirst number: ")
if first_number == 'q':
break
second_number = input("Second number: ")
try: ❶
answer = int(first_number) / int(second_number)
except ZeroDivisionError: ❷
print("You can't divide by 0!")
else: ❸
print(answer)
'''
我们让Python尝试执行try代码块中的除法运算(见❶),这个代码块只包含可能导致错误的代码。
依赖于try代码块成功执行的代码都放在else代码块中;在这个示例中,如果除法运算成功,
我们就使用else代码块来打印结果(见❸)。except代码块告诉Python,出现ZeroDivisionError异常时该怎么办(见❷)。
如果try代码块因除零错误而失败,我们就打印一条友好的消息,告诉用户如何避免这种错误。程序将继续运行,
用户根本看不到traceback:
Give me two numbers, and I'll divide them.
try:
工程(预测的可能发生错误的代码)
except:
try代码块错误时的方法
else:
try代码块成功执行时运行
'''
#3.5 处理 FileNotFoundError异常
#处理文件时,一种常见问题是找不到文件:
#现在来尝试读取一个不存在的文件
alice.py
filename ='alice.txt'
with open(filename)as f_object:
contents = f_obj.read()
#py无法读取不存在的文件。因此他引发一个异常:
#FileNotFoundError异常
#py找不到目标文件时创建的异常
#这个错误在这个实例中是open函数导致的
#所以我们使用try语句处理时,需要把open()放在try中
filename = 'alice.txt'
try:
with open(filename)as f_obj:
contents = f_obj.read()
except FileNotFoundError:
msg = '对不起,这个文件'+filename+'找不到或者根本没存在过'+filename
print(msg)
#但如果文件不存在的话这个异常处理的意义不大
#3.6 分析文本
##你可以分析包含整本书的文本文件。很多经典文学作品都是以简单文本文件的方式提供的,因为它们不受版权限制。
#下面来尝试提取童话爱丽丝梦游仙境的字符串并计算它包含多少个单词
#调用split()方法-->根据一个字符串创建一个单词列表
title = '爱丽丝梦游仙境'
title.split()
#输出:
['爱','丽','丝','梦','游','仙','境']
#方法split()以空格为分隔符将字符串分拆成多个部分,并将这些部分都存储到一个列表中
split() 方法语法:
str.split(str="", num=string.count(str)).
参数
str -- 分隔符,默认为所有的空字符,包括空格、换行(\n)、制表符(\t)等。
num -- 分割次数。默认为 -1, 即分隔所有。
#对整篇小说调用此方法:
filename='平凡的世界.txt'
try:
with open(filename) as f_obj:
contents = f_obj.read()
except FileNotFoundError:
msg ='对不起,文件'+filename+'并不存在!'
print(msg)
else:#try通过时才执行else中的代码
#计算文件大致包含多少个单词
words = contents.split()
num_words = len(words)
print('文件'+filename+'大约有'+str(num_words)+'个字')
#3.7 使用多个文件
#创建一个专门用于文本分析的函数,便于调用
word_count.py
def count_words(filename):
'''计算一个文件大致包含多少个单词'''
try:
with open(filename)as f_obj:
contents = f_obj.read()
except FileNotFoundError:#文件不曾存在时的解决方案
msg = '对不起文件:'+filename+'不存在'
print(msg)
else:
#计算文件大致包含多少个单词
words = contents.split()
num_words = len(words)
print('文件'+filename+'有'+str(num_words)+'个单词')
filename = '平凡的世界.txt'
count_words(filename)
#现在可通过编写一个简单的循环,计算要分析的任何文本包含多少个单词了
#我们将要分析的文件的名称存储在一个列表中,然后对列表中的每个文件都调用count_words()
from word_count.py import count_words()
filenames = ['平凡的世界.txt','消失.txt','半岛铁盒.txt']
for filename in filenames:
count_words(filename)
#3.8失败时一声不吭
#在except代码块中明确地告诉python啥也不做,Python有个pass语句,可在代码块中使用它来让python什么都不要做
def count_words(filename):
'''计算一个文件大致包含多少个单词'''
try:
--snip--
except FileNotFoundError:
pass
else:
--snip--
filenames = ['平凡的世界.txt','消失.txt','半岛铁盒.txt']
for filename in filenames:
count_words(filename)
#相比于前一个程序,这个程序唯一不同的地方是pass语句
#现在当出现FileNotFoundError异常时,将执行except代码块中的代码,但什么都不会发生。
#这种错误发生时,不会出现traceback也没有任何输出
#pass语句还充当了占位符,它提醒你在程序的某个地方什么都没做,并且以后有可能在这里做点什么
#如在这个程序中我们可将找不到的文件名称写入到文件missing_files.txt中
#3.9 决定报告哪些错误
#可控制与用户分享错误信息的程度,要分享多少信息由你决定
#凭借经验可判断该在程序的什么地方包含异常处理块,以及出现错误时该向用户提供多少相关信息
10-6加法运算
msg_1 = '请输入1个数字'
msg_2 = '请输入1个数字'
try:
a = input(msg_1)
b = input(msg_2)
c= a+b
except ValueError:
print('只能输入数字')
else:
print(c)
10-7加法计算器:
msg_1 = '请输入1个数字'
while True:
try:
a = int(input(msg_1))
b = int(input(msg_1))
c= a+b
except ValueError:
print('只能输入数字')
else:
print(c)
10-8 猫和狗
filenames = ['小猫.txt','小狗.txt']
for filename in filenames:
try:
with open(filename) as dq:
contents = dq.readlines()
print(contents)
except FileNotFoundError:
print(filename+'文件并不存在')
pass
else:
for line in contents:
print(line.rstrip())
'''
你可以使用方法count()来确定特定的单词或短语在字符串中出现了多少次。例如,下面的代码计算'row'在一个字符串中出现了多少次:
line = "Row, row, row your boat"
line.count('row')
2
line.lower().count('row')
3
请注意,通过使用lower()将字符串转换为小写,可捕捉要查找的单词出现的所有次数,而不管其大小写格式如何。
'''
10.4存储数据
一种简单的方式是使用模块json来存储数据
模块json让你能够将简单的Python数据结构转储到文件中,
并在程序再次运行时加载该文件中的数据。你还可以使用json在Python程序之间分享数据。
而且JSON数据格式并非py专用,你可以将JSON格式存储的数据与使用其他编程语言的人分享
'''
JSON(JavaScript Object Notation)格式最初是为JavaScript开发的,
但随后成了一种常见格式,被包括Python在内的众多语言采用。
'''
4.1 使用json.dump()和json.load()
#编写一个存储一组数字的简短程序json.dump(),再编写一个将这些数字读取到内存中的程序json.load()
#函数json.dump()接受两个实参:
#要存储的数据
#可用于存储数据的文件对象
number_Write.py
import json #导入模块json
numbers = [2,3,5,8,11]#创建一个数字列表
filename = 'number.json'
#指定要将该数字列表存储到其中的文件的名称
#通常使用文件扩展名.json来指出文件存储的数据为JSON格式
with open(filename,'w')as f_obj:
#以写入模式打开这个文件,让json能够将数据写入其中
json.dump(numbers,f_obj)
#使用函数json.dump()将数字列表存储到文件numbers.json中
#接下来编写一个程序,使用json.load()将这个列表读取到内存中:
number_reader.py
import json
filename = 'numbers.json'
with open(filename)as f_obj:#这一次我们用读取的方式打开这个文件
numbers = json.load(f_obj)
#我们使用函数json.load()加载存储在numbers.json中的信息,并将其存储到变量numbers中
print(numbers)
4.2保存和读取用户生成的数据
使用json保存他们大有益处,因为如果不以某种方式进行存储,等程序停止运行时用户的信息将丢失
如来存储一个用户的名字
remember_me.py
import json
username = input("What is your name? ") ❶
filename = 'username.json'
with open(filename, 'w') as f_obj:
json.dump(username, f_obj) ❷
print("We'll remember you when you come back, "+username+"!") ❸
现在再编写一个程序,向其名字被存储的用户发出问候:
greet_user.py
import json
filename = 'username.json'
with open(filename) as f_obj:
username = json.load(f_obj) ❶
print("Welcome back, "+username+"!") ❷
现在把两个程序合二为一
remember_me.py
import json
如果以前存储了用户名,就加载它
否则,就提示用户输入用户名并存储他
filename = 'username.json'
try:
with open(filename)as f_obj:
username=json.load(f_obj)
except FileNotFoundError:
username= input('你叫啥')
with open(filename,'w')as f_obj:
json.dump(username,f_obj)
print('我们将会记住你的名字'+username+'!')
else:
print('欢迎回来'+username+'!')
4.3重构
代码能够工作后,还可做进一步的改进
#将代码划分为一系列完成具体工作的函数。
# 这样的过程被称为重构。
# 重构让代码更清晰、更易于理解、更容易扩展。
重构remember_me.py
#此程序的重点是问候用户,因此我们可将大部分逻辑放到一个或多个函数中如greet_user()
remember_me.py
def greet_user():
'''问候用户,并指出其名字'''
filename = 'username.json'
try:
with open(filename)as f_obj:
username = json.load(f_obj)
except FiliNotFoundError:
username= input('你叫啥')
with open(filename,'w')as f_obj:
json.dump(usernam,f_obj)
print('我们将会记住你的名字'+username+'!')
else:
print('欢迎回来!'+username+'!')
greet_user()
重构greet_user(),让它不执行这么多任务
首先我们将获取存储的用户名的代码移到另一个函数中:
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 greet_user():
"""此函数目标:问候用户,并指出其名字"""
username = get_stored_username()
if username: ❸
print("Welcome back, "+username+"!")
else:
username = input("What is your name? ")
filename = 'username.json'
with open(filename, 'w') as f_obj:
json.dump(username, f_obj)
print("We'll remember you when you come back, "+username+"!")
greet_user()
我们还需要将greet_user()中的另一个代码块提取出来:将没有存储用户名时提示用户输入的代码放在一个独立的函数中:
import json
def get_stored_username():
"""如果存储了用户名,就获取它"""
--snip--
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()
10-11喜欢的数字
10-12记住喜欢的数字
-- coding: UTF-8 --
import json
def jlsz():
try:
favorite_num = int(input('输入一个你喜欢的数字'))
except:
print('请输入数字,而不是文字!')
else:
filename ='shuzi.json'
with open(filename,'w')as f_obj:
json.dump(favorite_num,f_obj)
return favorite_num
def dqsz():
filename = 'shuzi.json'
try:
with open(filename)as f_obj:
favorite_num = json.load(f_obj)
except FileNotFoundError:
print('对不起数据库中没有记录')
jlsz()
else:
print('你最喜欢的数是:'+str(favorite_num))
dqsz()
10-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("当前用户名为, "+username+"!")
a = input('用户名正确吗?yes/no')
if a == 'yes':
print(" 欢迎回来, " + username + "!")
else:
username = get_new_username()
print("好了我们记住你了!, " + username + "!")
else:
username = get_new_username()
print("We'll remember you when you come back, "+username+"!")
greet_user()
第11章 测试代码
#oython模块unittest中的工具来测试代码
1.1测试函数
1.单元测试和测试用例
#python标准库中的模块unittest提供了代码测试工具
#单元测试用于核实函数的某个方面没有问题
#测试用例是一组单元测试,这些单元测试一起核实函数在各种情形下的行为都符合要求
#全覆盖测试涵盖了各种可能的函数使用方式,通常只需针对代码的重要行为编写测试即可,等项目被广泛使用时再考虑全覆盖
2.可通过的测试
#创建测试用例的语法需要一段时间才能习惯,但测试用例创建后,在添加针对函数的单元测试就很简单了
#要为函数编写测试用例,可先导入模块unittest以及要测试的函数,在创建一个继承unittest.TestCase的类,并编写一系列方法对函数行为的不同方面进行测试
下面是一个只包含一个方法的测试用例,它检查函数get_formatted_name()在给定名和姓时能否正确地工作:
test_name_function.py
import unittest#导入模块和要测试的函数
from name_function import get_formatted_name
class NamesTestCase(unittest.TestCase): ❶#创建一个名为NamesTestCase的且继承unittest.TestCase的类,用于
包含一系列针对get_formatted_name()的单元测试
"""测试name_function.py"""
def test_first_last_name(self):
"""能够正确地处理像Janis Joplin这样的姓名吗?"""
formatted_name = get_formatted_name('janis', 'joplin') ❷
self.assertEqual(formatted_name, 'Janis Joplin') ❸
#一个断言方法。断言方法用来核实得到的结果是否与期望的结果一致。
#将formatted_name的值同字符串'Janis Joplin'进行比较,如果它们相等,就万事大吉,如果它们不相等,跟我说一声!
unittest.main()
我们运行testname_function.py时,所有以test打头的方法都将自动运行
类名可以不要求以test开头,但最好是包含Test,然而
在编写方法名时一定要以小写test开头,因为在继承的unnit.TestCase类中会默认去找以test开头的方法自动运行
测试通过时会显示ok等
3.不能通过的测试
#若测试没有通过结果是怎么样的呢
#我们故意让方法必须提供中间名
E ❶#输出一个字母E指出测试用例中有一个单元测试导致了错误
======================================================================
ERROR: test_first_last_name (__main__.NamesTestCase) ❷#接下来,我们看到NamesTestCase中的test_first_last_name()导致了错误
----------------------------------------------------------------------
Traceback (most recent call last): ❸#在❸处,我们看到了一个标准的traceback,
#它指出函数调用get_formatted_name('janis', 'joplin')有问题,因为它缺少一个必不可少的位置实参。
File "test_name_function.py", line 8, in test_first_last_name
formatted_name = get_formatted_name('janis', 'joplin')
TypeError: get_formatted_name() missing 1 required positional argument: 'last'
----------------------------------------------------------------------
Ran 1 test in 0.000s ❹
FAILED (errors=1) ❺
4.测试未通过时怎么办
#测试未通过时,不要修改测试,而应修复导致测试不能通过的代码:
# 检查刚对函数所做的修改,找出导致函数行为不符合预期的修改。
#我们只需要让中间名变为可选的,同时这个函数还能接受中间名
#要将中间名设置为可选的,可在函数定义中将形参移到形参列表末尾,并将其默认值指定为一个空字符串
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()
#再次运行test_name_function.py:
#现在测试通过了
5.添加新测试
#确定get_formatted_name()又能正确地处理简单的姓名后,我们再编写一个测试,用于测试包含中间名的姓名
#为此我们在NamesTestCase类中再添加一个方法:
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()
#方法名必须以test_打头,这样它才会在我们运行test_name_function.py时自动运行。
# 这个方法名清楚地指出了它测试的是get_formatted_name()的哪个行为,这样,如果该测试未通过,
# 我们就会马上知道受影响的是哪种类型的姓名。在TestCase类中使用很长的方法名是可以的;这些方法的名称必须是描述性的,
# 这才能让你明白测试未通过时的输出;这些方法由Python自动调用,你根本不用编写调用它们的代码。
11-1城市和国家
city_functions.py
def city_functions(city,country):
full = city+','+country
return full
test_cities.py
-- coding: UTF-8 --
import unittest
from city_functions import city_functions
class NamesTestCase(unittest.TestCase):
def test_city_country(self):
'''能够调用函数得到预期结果'''
full_msg = city_functions('彭水','重庆')
print(full_msg)
self.assertEqual(full_msg,'彭水,重庆')
unittest.main()
11-2人口数量
city_functions.py
def city_functions(city,country,population=''):
if population:
full = city+','+country+population
else:
full = city+','+country
return full
test_cities.py
-- coding: UTF-8 --
import unittest
from city_functions import city_functions
class NamesTestCase(unittest.TestCase):
def test_city_country(self):
'''能够调用函数得到预期结果'''
full_msg = city_functions('彭水','重庆','5000')
print(full_msg)
self.assertEqual(full_msg,'彭水,重庆5000')
unittest.main()
11.2测试类
----> 编写针对类的测试,如果针对类的测试通过了,你就能确信对类所做的改进没有意外地破坏其原有的行为
#各种断言方法
#表11-1描述了6个常用的断言方法。
#只能在继承unittest.TestCase的类中使用这些方法,下面来看看如何在测试类时使用其中的一个。
表11-1 unittest Module中的断言方法
方法 用途
|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|
2.2一个要测试的类
你所做的大部分工作都是测试了类中方法的行为,但存在一些不同之处,下面来编写一个类进行测试
survey.py
class AnonymousSurvey():
'''收集匿名调查问卷的答案'''
def init(self,question):
'''存储一个问题,并为存储答案做准备'''
self.question = question
self.response = []#创建一个空列表,用于存储答案
def show_question(self):
'''显示调查问卷'''
print(self.question)
def store_response(self,new_response):#在答案列表中添加新答案的方法
'''存储单份调查答卷'''
self.response.append(new_response)
def show_results(self):#将存储在列表中的答案都打印出来的方法
'''显示收集到的所有答案'''
print('调查结果是:')
for response in self.responses:
print('-'+response)
'''要创建类的实例,只需提供一个问题即可'''
下面来使用这个程序
language_survey.py
from survey import AnonymousSurvey
定义一个问题并创建一个表示调查的AnonymousSurvey对象
question = '什么语言是你的母语'
my_survey = AnonymousSurvey(question)
显示问题并存储答案
my_survey.show_question()
print(''输入'q'退出程序'')
while True:
response = input('语言:')
if response =='q':
break
my_survey.store_response(response)
显示调查结果
print('谢谢你参与调查!')
my_survey.show_results()
2.3测试AnonymousSurvey类
-->下面来编写一个测试,对AnonymousSurvey类的行为的一个
方面进行验证:如果用户面对调查问题时只提供了一个答案,这个答案也能被妥善地存储。为此,我们将在这个
答案被存储后,使用方法assertIn()来核实它包含在答案列表中:
test_survey.py
import unittest
from survey import AnonymousSurvey
calss TestAnonymousSurvey(unittest.TestCase):
'''针对AnonymousSurvey类的测试'''
def test_store_single_response(self):
'''测试单个答案会被妥善地存储'''
question = '什么语言是你的母语'
my_survey = AnonymousSurvey(question)
my_survey.store_response('英语')
self.asserIn('英语',my_survey.responses)
unittest.main()
下面进行优化确保用户提供三个答案时,他们也将被妥善地存储,为此我们在Tes…中添加一个方法:
import unittest
from survey import AnonymousSurvey
calss TestAnonymousSurvey(unittest.TestCase):
'''针对AnonymousSurvey类的测试'''
def test_store_single_response(self):
'''测试单个答案会被妥善地存储'''
--snip--
def test_store_three_responses(self):
'''测试三个答案会被妥善地存储'''
question = '你的母语是啥'
my_survey = AnonymousSurvey(question)
responses = ['中文','英语','法语']
for response in responses:
my_survey.store_response(response)
for response in responses:
self.assertIn(response,my_survey.responses)
unittest.main()
这种做法的效果很好,但这些测试有些重复的地方-每个测试方法中都创建了一个AnoonymousSurvey实例,下面使用unittest的另一项功能来提高他们的效率
2.4方法setUp()
#unittest.TestCase类中包含了方法setUp(),py将先运行它,再运行各个以test_打头的方法
#如此以来,在你编写的每个测试方法中都可使用在方法setUp()中创建的对象了
#下面使用setUp()来创建一个调查对象和一组答案,供方法test_store_single_response()test_store_three_responses()使用:
import unittest
from survey import AnonymousSurvey
class TestAnonymousSurvey(unittest.TestCase):
'''针对AnonymousSurvey类的测试'''
def setUp(self):
'''创建一个调查对象和一组答案,供使用的测试方法使用'''
question = '你的母语是什么'
self.my_survey = AnonymousSurvey(question)#1
self.responses = ['中文','英语','法语']#2
def test_store_single_response(self):
'''测试单个答案会被妥善地存储'''
self.my_survey.store_response(self.responses[0])
self.asssertIn(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()做了两件事情:创建一个调查对象(1);创建一个答案列表(2)
##存储这两样东西的变量名包含前缀self(即是存储在属性中),因此可在这个类的任何地方使用。
##这让两个测试方法都更简单,因为他们都不用创建调查对象和答案
测试自己编写的类时,方法setUp()让测试方法编写起来更容易:可在setUp()方法中创建一系列实例并设置它们的属性,
##再在测试方法中直接使用这些实例。相比于在每个测试方法中都创建实例并设置其属性,这要容易得多
'''
运行测试用例时,每完成一个单元测试,Python都打印一个字符:
测试通过时打印一个句点;测试引发错误时打印一个E;测试导致断言失败时打印一个F。
这就是你运行测试用例时,在输出的第一行中看到的句点和字符数量各不相同的原因。
如果测试用例包含很多单元测试,需要运行很长时间,就可通过观察这些结果来获悉有多少个测试通过了。
'''
11-3雇员
z.py
class Employee():
'''编写雇员类'''
def init(self,name,xing,salary):
self.name = name
self.xing = xing
self.salary = salary
def give_raise(self,a=5000):
self.salary += a
ceshi.py
import unittest
from z import Employee
class TestEmployee(unittest.TestCase):
'''针对雇员类的测试'''
def setUp(self):
'''创建新的雇员实例,避免重复创建'''
self.employee = Employee('rhz','jay',50000)
def test_give_default_raise(self):
'''工资默认增长'''
a = self.employee.salary#获取当前工资值
self.employee.give_raise()
self.assertEqual(self.employee.salary,a+5000)
def test_give_custom_raise(self):
'''工资自定义增长'''
a = self.employee.salary#获取当前工资值
self.employee.give_raise(10000)#工资加10000
self.assertEqual(self.employee.salary,a+10000)
unittest.main()
作为初学者并非必须为你尝试的所有项目编写测试,但参与工作量较大的项目时,你应该对自己编写的函数和类的重要行为进行测试
这样你就能更加随心所欲的改进既有代码了,如果不小心破坏了原来的功能,你马上就会知道,从而能够轻松的维护代码
如果你在项目中包含了初步测试,其他程序员将更敬佩你与你合作,
如果你要和别的程序员合作开发代码,就必须证明你编写的代码通过了既有的测试,通常还需要为你添加的新行为编写测试
#通过多开展测试来熟悉代码测试过程,对于自己编写的函数和类,请编写针对其重要行为的测试,不要试图去编写全覆盖的测试用例,除非有充分理由这样做
第二部分---项目
具有了一定寄出后可以开始着手开发有意思的交互式项目了
#本部分包含三个不同类型的项目
1.使用python开发游戏--外星人入侵(12-14章)--2d游戏--使用pygame开发2d游戏
2.数据可视化--始于第15章--使用Matplotlib和Pygal来生成数据-以及根据这些数据创建实用而漂亮的图表
##第16章介绍如何从网上获取数据,并给他们提供可视化包以创建天气图和交易收盘价图
##第17章介绍如何编写自动下载数据并对其进行可视化的程序--学习可视化让你可以探索数据挖掘领域-目前在全球都非常吃香的一个技能
3.Web应用程序(18-20章)
##使用Django包创建Web程序
##还可部署程序,供用户访问
##有基础后可选择深入学习其他有关如何使用Django开发应用程序的资料
项目1外星人入侵
第12章武装飞船
#Pygame,这是一组功能强大而有趣的模块,可用于管理图形、动画乃至声音,让你能够更轻松地开发复杂的游戏。
#通过pygame来处理在屏幕上绘制图像等任务,不用考虑众多繁琐的编码工作,重点将被放在高级逻辑上
#通过编写简单的游戏有助于明白专业级游戏是怎么编写出来的
#请将游戏<外星人入侵>将包含很多不同的文件,所以请将他们统一安排在文件夹alien_invasion中,这样好方便后期导入啥的
12.1规划项目
#开发大型项目时,做好规划后再动手很重要。
#规划可确保你不偏航,从而提高项目成功的可能性
下面是关于这个游戏的描述:
在游戏《外星人入侵》中,玩家控制着一艘最初出现在屏幕底部中央的飞船。
玩家可以使用箭头键左右移动飞船,还可使用空格键进行射击。游戏开始时,一群外星人出现在天空中,他们在屏幕中向下移动。
玩家的任务是射杀这些外星人。玩家将所有外星人都消灭干净后,将出现一群新的外星人,他们移动的速度更快。
只要有外星人撞到了玩家的飞船或到达了屏幕底部,玩家就损失一艘飞船。玩家损失三艘飞船后,游戏结束。
12.2安装Pygame
#https://bitbucket.org/pygame/pygame/downloads/
12.3开始游戏项目
12.3.1创建Pygame窗口以及响应用户输入
首先,我们创建一个空的Pygame窗口。使用Pygame编写的游戏的基本结构如下:
alien_invasion.py
import sys#玩家退出时,我们将使用模块sys来退出游戏
import pygame#模块pygame包含开发游戏所需的功能
def run_game():
# 初始化游戏并创建一个屏幕对象
pygame.init() ❶#此处代码初始化背景设置,让pygame能够正确工作
screen = pygame.display.set_mode((1200, 800)) ❷
创建一个名为screen的显示窗口,这个游戏的所有图形元素都
将在其中绘制,实参(1200,800)是一个元组,指定了游戏窗口的尺寸,对象screen是一个surface
,在pygame中是屏幕的一部分,用于显示游戏元素,在这个游戏中每个元素(如外星人或飞船)都是一个surface
display.set_mode()返回的surface表示整个游戏窗口。我们激活游戏的动画循环后,没经过一次循环都将自动重绘这个surface
pygame.display.set_caption("Alien Invasion")
# 开始游戏的主循环
while True: ❸#
# 监视键盘和鼠标事件
for event in pygame.event.get(): ❹
#为访问Pygame检测到的事件,我们使用方法pygame.event.get()
#所有键盘和鼠标事件都将促使for循环运行
#事件循环,侦听事件,并根据发生的事件执行相应的任务
if event.type == pygame.QUIT: ❺
#编写一系列的if语句来检测并响应特定的事件
sys.exit()
#检测到pygame.QUIT事件,我们调用sys.exit()来退出游戏
# 让最近绘制的屏幕可见
pygame.display.flip() ❻
#调用了pygame.display.flip(),命令Pygame让最近绘制的屏幕可见。
#在这里,他在每次执行while循环时都绘制一个空屏幕,并擦去旧屏幕,使得只有新屏幕可见
#在我们移动游戏元素时,pygame.display.flip()将不断更新屏幕,以显示元素的新位置,并在原来的位置隐藏元素
#从而营造平滑移动的效果
run_game()
#初始化游戏并开始主循环
12.3.2设置背景色
pygame默认设置一个黑色屏幕,下面来设置另一种颜色
alien_invasion.py
--snip--
def run_game():
--snip--
pygame.display.set_caption('Alien Invasion')
#设置背景色
bg_color = (230,230,230)
#在Pygame中颜色是以RGB值规定的,这种颜色由三原色值组成
#每个值的可取范围都是0-255
#通过组合不同的RGB值可以创建1600万种颜色
#在颜色值(230, 230, 230)中,红色、蓝色和绿色量相同,它将背景设置为一种浅灰色。
#创建背景色并将其存储在bg_color中,
#该颜色只需指定一次,因此我们在进入主while循环前定义它
#开始游戏主循环
while True:
#监听键盘和鼠标事件
--snip--
#每次循环时都将重绘屏幕
screen.fill(bg_color)
#调用方法screen.fill(),用背景色填充屏幕,这个方法只接受一个实参:一种颜色
#让最近绘制的屏幕可见
pygame.display.flip()
run_game()
12.3.3创建设置类
#每次给游戏添加新功能时,通常也引入一些新设置
下面来编写一个名为settings的模块,其中包含一个名为Settings的类--
#用于将所有设置存储在一个地方,以免在代码中到处添加设置
#这样我们就能传递一个设置对象,而不是众多不同的设置
#另外这让函数调用更简单,且在项目增大时修改游戏的外观更容易:
#要修改游戏,只需修改settings.py中的一些值,而无需查找散布在文件中的不同设置
settings.py
class Settings():
'''存储《外星人入侵》的所有设置的类'''
def init(self):
'''初始化游戏的设置'''
#屏幕设置
self.screen_width = 1200
self.screen_height = 800
self.bg_color = (230,230,230)
alien_invasion.py
--snip--
import pygame
from settings import Settings
def run_game():
'''初始化pygame,设置和屏幕对象'''
pygame.init()
ai_settings = Settings()
#创建一个Settings实例,并将其存储在变量ai_settings中
screen = pygame.display.set_mode((ai_settings.screen_width,ai_settings.screen_height))
#创建屏幕时使用了ai_settings的属性screen_width和screen_height
pygame.display.set_caption('Alien Invasion')
开始游戏主循环
while True:
--snip--
#每次循环时都重绘屏幕
screen.fill(ai_settings.bg_color)#填充屏幕时,也使用了ai_settings来访问背景色
#让最近绘制的屏幕可见
pygame.display.flip()
run_game()
12.4添加飞船图像
#为了在屏幕上绘制玩家的飞船,我们将加载一幅图像,在使用Pygame方法blit()绘制它
#为游戏选择素材时务必注意版权
#在游戏中几乎可以使用任何类型的图形文件,但使用位图(.bmp)文件最为简单,因为Pygame默认加载位图。
#虽然可配置Pygame以使用其他文件类型,但有些文件类型要求你在计算机上安装相应的图像库
#可将其他图像通过软件转换为.bmp位图
#选择图像时尽可能选择背景透明的图像,这样好给图像上色
http://www.ituring.com.cn/book/1861---配套资源---在文件夹内新建一个名为images的文件夹并将ship.bmp保存到这个文件夹中
12.4.1 创建Ship类
#选择飞船图像后我们需要将他显示到屏幕上,创建一个名为ship的模块其中包含Ship类,它负责管理飞船的大部分行为
ship.py
import pygame
class Ship():
def init(self,screen):#screen指定了要将飞船绘制到什么地方
'''初始化飞船并设置其初始值'''
self.screen = screen
#加载飞船图像并获取其外接矩形
self.image = pygame.image.load('images/ship.bmp')
#pygame.image.load()加载图像,这个函数返回一个表示飞船的surface,而我们就将这surface存储到了self.image中
self.rect = self.image.get_rect()
#加载飞船后我们使用get_rect()获取相应surface的属性rect
#处理rect对象时,可使用矩形四角和中心的x和y坐标。可通过设置这些值来指定矩形的位置。
---->***1
self.screen_rect = screen.get_rect()
#将表示屏幕的矩形存储在self.screen_rect中
**将每艘飞船图像放在屏幕底部中央**
self.rect.centerx = self.screen_rect.centerx
#将self.rect.centerx(飞船中心的x坐标)设置为表示屏幕的矩形的属性centerx
self.rect.bottom = self.screen_rect.bottom
#将self.rect.bottom(飞船下边缘的y坐标)设置为表示屏幕的矩形的属性bottom
def blitme(self):
'''在指定位置绘制飞船'''
self.screen.blit(self.image,self.rect)
'''
Pygame的效率之所以如此高,一个原因是它让你能够像处理矩形(rect对象)一样处理游戏元素,即便它们的形状并非矩形。
像处理矩形一样处理游戏元素之所以高效,是因为矩形是简单的几何形状。
# 这种做法的效果通常很好,游戏玩家几乎注意不到我们处理的不是游戏元素的实际形状。
***1
要将游戏元素居中,可设置相应rect对象的属性center、centerx或centery。要让游戏元素与屏幕边缘对齐,
可使用属性top、bottom、left或right;
要调整游戏元素的水平或垂直位置,可使用属性x和y,它们分别是相应矩形左上角的x和y坐标。
'''
注意 在Pygame中,原点(0, 0)位于屏幕左上角,向右下方移动时,坐标值将增大。
在1200×800的屏幕上,原点位于左上角,而右下角的坐标为(1200, 800)。
文章评论