python编程从入门到实践阅读笔记

环境

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

注释

单行注释: #

多行注释 : ‘’’ … ‘’’ 或者 “” … “”"

变量和简单数据类型

python变量的命名和使用

  • 变量名只能包含字母、数字、下划线。变量名不可以以数字打头。
  • 不可以使用python关键字和函数名用作变量名。

字符串

python中引号扩起的内容都是字符串,其中的引号可以是单引号或双引号,

message = "I told my frind, 'python is my favorite language' "

使用字符串的方法

  1. 用方法修改字符串的大小写

    name = "ada lovelace"
    print(name.title())
    
    # Ada Lovelace
    

    方法是python可对数据执行的操作。每个方法后面都跟着一对括号便于传参。

    title() 方法以首字母大写的方式显示每个单词。

more :

upper() #全部大写
lower() #全部小写
  1. 合并(连接) 字符串

使用 + 来合并字符串 。

first_name = "ada" 
last_name = "lovelace" 
full_name = first_name + " " + last_name 
print(full_name)
  1. 制表符或换行符来添加空白

制表符 : \t

换行符 :\n

'''
预期效果 :
Languages:
	Python
	C
	JavaScript
'''
print("Languages:\n\tPython\n\tC\n\tJavaScript")
  1. 删除空白

空白很重要,因为需要比较两个字符串是否相同。例如在用户登录时检查其用户名。

python能够找出字符串开头和末尾多余的空白。

末尾没有空白 : 方法 rstrip() ,

开头没有空白 :方法 lstrip()

两边都没有空白 :方法 strip()

注意以上方法都返回剔除空白后的结果,需要重新存会变量中。

favourite_language = 'python ' 
favourite_language = favourite_language.rstrip()

数字

整数

** 表示乘方运算

运算 :±*/ (注意python3中 3/2 结果为 1.5)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

浮点数

python将带小数点的数字都称为浮点数。注意运算结果包含的小数位数可能是不确定的

使用函数 str() 避免类型错误。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这是一个类型错误,意味着python无法识别你使用的信息。

python发现你使用了一个值为int的变量,但它不知道该如何解读这个值,python知道这个变量表示的可能是数值23,也可能是字符2和3 。像上面这样在字符串中使用整数时,需要显式地指出你希望python将这个整数用作字符串。

调用函数 str() ,将非字符串值表示为字符串

age = 23
message = "Happy" + str(age) + "Birthday!"

print(message)

列表

列表由一系列按特定顺序排列的元素组成 。列表中的元素之间可以没有任何关系。

用方括号表示列表,并用逗号来分隔其中的元素 。

bicycles = [ "trek" , "cannondale" , "redline" , "specialized"]
print(bicycles)

# output :
# [ "trek" , "cannondale" , "redline" , "specialized"] python 将打印列表的内部表示,包括方括号。

列表基本操作

访问列表元素
print(bicycles[0])
  • python 第一个列表元素的索引为0
  • 通过将索引指定为 -1 ,可让python返回最后一个列表元素。
    • 这种约定也使用于其它附属索引,例如 索引 - 2 返回倒数第二个列表元素 索引 -3 返回倒数第三个列表元素。
修改、添加、删除元素

你创建的大多数列表都将是动态的 。例如你创建一个游戏,要求玩家射杀从天而降的外星人 ;为此,可在开始时将一些外星人存储在列表中,然后每当有外星人被射杀时,都将其从列表中删除,而每次有新的外星人出现在屏幕上时,都将其添加到列表中。整个游戏运行期间,外星人列表的长度将不断变化。

修改元素

与访问列表元素的语法类似 。可指定列表名和要修改的元素的索引

motorcycles = ['honda','yamaha','suzuki']
motorcycles[0] = 'ducati'

print(motorcycles)

添加元素

  1. 在列表末尾添加元素

使用方法 append( value )

motorcycles = ['honda','yamaha','suzuki']
motorcycles.append('ducati')

方法 append() 可动态地创建列表 。例如你可以先创建一个空列表,再使用一系列的 append() 语句添加元素 。

motorcycles = []
motorcycles.append('honda')
motorcycles.append('yamaha')
motorcycles.append('suzuki')

这种创建列表的方式极其常见,因为经常要等程序运行后,才知道用户要在程序中存储哪些数据。为控制用户, 可首先创建一个空列表,然后将用户提供的每个新值添加到列表中 。

  1. 在列表中插入元素

使用方法 insert( index ,value ) 可以在列表的任何位置添加新元素 。这种操作将列表中既有的每个元素都右移一个位置 。

motorcycles = ['honda','yamaha','suzuki']
motorcycles.insert(0,'ducati')
#此时motorcycles = ['ducati' , 'honda' , 'yamaha' , 'suzuki' ]

删除

你可以根据位置或值来删除列表中的元素

  1. 使用del 语句删除元素

知道要删除的元素在列表中的位置时,可使用del语句。

motorcycles = ['honda','yamaha','suzuki']
del motorcycles[0]
print(motorcycles)

#  ['yamaha','suzuki']

使用 del 语句将值从列表中删除后,你就无法再访问它了 。

  1. 使用 pop() 方法删除元素

有时候,你要将元素从列表中删除,并接着使用它的值。例如,你可能需要获取刚被射杀的外星人的x和y坐标,以便在响应的位置显示爆炸效果; 在web应用程序中,你可能要将用户从活跃成员列表中删除,并将其加入到非活跃成员列表中。

方法 pop() 删除列表末尾的元素,并允许你继续使用

pop就源自这样的类比:列表就像一个栈,而删除列表末尾的元素相当于弹出栈顶元素。

motorcycles = ['honda','yamaha','suzuki']

popped_motorcycle = motorcycles.pop() 
print(poped_motorcycles)
#suzuki

  1. pop( index ) 弹出列表中任何位置处的元素

使用 pop() 来删除列表中任何位置的元素 ,只需在括号中指定要删除的元素的索引。

# 假设列表中的摩托车是按照购买时间存储的
motorcycles = ['honda','yamaha','suzuki']
last_owned = motorcycles.pop()
first_owned = motorcycles.pop(0)
print("The first motorcycle I owned is a " + first_owned.title() + "." )
# 注意使用 pop() 时被弹出的元素就不再在列表中了
  1. 根据值删除元素

使用方法 remove()

方法remove() 只删除第一个指定的值,如果要删除的值可能在列表中出现多次,就需要使用循环来判断是否删除了所有这样的值。

motorcycles = ['honda','yamaha','suzuki','ducati']
motorcycles.remove('ducati')

使用remove() 从列表中删除元素时,也可以接着使用它的值 。

motorcycles = ['honda','yamaha','suzuki','ducati']
too_expensive = 'ducati'
motorcycles.remove(too_expensive)

print("\nA " + too_expensive + " is too expensive to me. ")
# 值 'ducative' 已经从列表中删除,但它还存储在变量 too_expensive 中
组织列表
  1. 使用方法 sort() 对列表进行永久性排序
cars = ['bmw','audi','toyota','subaru']
cars.sort()
# ['audi', 'bmw', 'subaru', 'toyota']
# 按首字母顺序排列 ,且无法恢复到原来的排列顺序

还可以按与字母顺序相反的顺序排列列表元素 ,只需要向 sort() 方法传递参数 reverse = True

cars = ['bmw','audi','toyota','subaru']
cars.sort(reverse = True)
  1. 使用方法 sorted(list) 对列表进行临时排序

函数 sorted() 让你能够按特定顺序显示列表元素,同时不影响它们在列表中的原始排列顺序

cars = ['bmw','audi','toyota','subaru']
print(sorted(cars))
print(sorted(places, reverse=True))
  1. 反转列表元素顺序
cars = ['bmw','audi','toyota','subaru']
car.reverse()

reverse() 不是指按与字母顺序相反的顺序排列列表元素,而只是反转列表元素的排列顺序

  1. 确定列表的长度
cars = ['bmw','audi','toyota','subaru']
print( len(cars) )
遍历列表
magicians = ['alice', 'david', 'carolina']
for magician in magicians:
    print(magician)

python 首先获取列表 magicians 中的第一个值 ‘alice’ , 并将其存储到变量 magician 中。
接下来执行print ,由于该列表中还包含其他值,python返回到循环的第一行,python获取列表中的下一个名字,‘david’ ,并将其存储到变量 magician 中

在for循环中,每个缩进的代码行都是循环的一部分, 而没有缩进的代码行不是循环的内容

magicians = ['alice', 'david', 'carolina']
for magician in magicians:
    print(magician.title() + ", that was a great trick! ")
    print("I can't wait to see your next trick, " + magician.title() + ".\n")

python根据缩进来判断代码行与前一个代码行的关系

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

不要遗漏冒号 !!!

创建数值列表
  1. 函数 range()

range() 从你指定的第一个值开始数,并在到达你指定的第二个值后停止,!!输出不包含第二个值

for value in range(1,5):
    print(value)
    
"""
1
2
3
4
"""

使用函数 list() 将 range() 的结果直接转换为列表

numbers = list(range(1,6))
print(numbers)
# [1, 2, 3, 4, 5]

使用函数 range() 时,还可指定步长。

even_numbers = list(range(2,11,2))
print(even_numbers)
#[2, 4, 6, 8, 10]

more :

创建一个列表,其中包含前10个整数的平方

squares = [] 
for value in range(1,11) :
    square = value**2 
    squares.append(square)
    
print(squares)
  1. 简单的统计计算
digits = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]

min_digit = min(digit)
max_digit = max(digit)
sum_digit = sum(digit)

列表解析

列表解析允许你只编写一行代码就生成列表

列表解析将 for循环和创建新元素的代码合并成一行,并自动添加新元素

squares = [value**2 for value in range(1,11)]

方括号内结构 :

1.定义一个表达式用于生成你要存储到列表中的值

2.编写一个for循环,用于给表达式提供值

切片

处理列表的所有元素 – 切片

创建切片

要创建切片,可指定要使用的第一个元素和最后一个元素的索引。与 range() 函数一样,python在到达你指定的第二个索引前面的元素后停止

players = ['charles', 'martina', 'michael', 'fkirebce', 'eli']
print(players[0:3])

#  ['charles', 'martina', 'michael']

你可以生成列表的任何子集,例如如果你要提取列表的第 2-4 个元素,可将起始索引指定为1 ,并将终止索引指定为4 。

print(players[:4]) # 不指定起始索引 python会从列表开头开始提取
print(players[2:]) # 提取从第三个元素到列表末尾的所有元素

print(players[-3:]) #打印列表最后三名成员的名字
遍历切片
players = ['charles', 'martina', 'michael', 'fkirebce', 'eli']

for player in players[:3]:
    print(player.title())

在很多情况下切片都很有用。

例如,编写游戏时,你可以在玩家退出游戏时将其最终得分加入到一个列表中,然后为获取该玩家的三个最高得分,你可以将该列表降序排列 ,再创建一个只包含前三个得分的切片 。

处理数据时可以利用切片来批量处理 ;

编写web应用程序时 ,可使用切片来分页显示信息,并在每页显示数量合适的信息 。

复制列表

要复制列表,可创建一个包含整个列表的切片 ,方法是**同时省略起始索引和终止索引 [ : ] **

my_foods = ['pizza', 'falafel', 'carrit cake']
friend_foods = my_foods[ : ]

my_foods.append('cannoli')
friend_foods.append('ice cream')

print("My favourite foods are: ")
print(my_foods)

print("My friend's favourite foods ard: ")
print(friend_foods)

""" 
My favorite foods are:
 ['pizza', 'falafel', 'carrot cake', 'cannoli']
My friend's favorite foods are:
 ['pizza', 'falafel', 'carrot cake', 'ice cream']
 
 表明此时存在两个表 。
 倘若我们只是简单地将 my_foods 赋给 friend_foods ,就不能得到两个列表
"""

易犯的错误 :

friend_foods = my_foods

这里将 my_foods 赋给 friend_foods , 而不是将 my_foods 的副本存储到 friend_foods ,这种语法实际上是让python将新变量 friend_foods 关联到包含在 my_foods 中的列表,因此这两个变量都指向同一个列表

元组

列表非常适合用于存储在程序运行期间可能变化的数据集。 列表是可以修改的,这对处理网站的用户列表或游戏中的角色列表至关重要 。然而有时候你需要创建一系列不可修改的元素

不可变的列表称为元组

元组看起来和列表相似 ,但使用圆括号而不是方括号来表示 。

定义元组后 ,就可以使用索引来访问其元素 ,就像访问列表元素一样。

例如,如果有一个大小不应改变的矩形 ,可将其长度和宽度存储在一个元组中 ,从而确保它们是不能修改的 。

dimensions = (200, 50)
print(dimensions[0])
print(dimensions[1])

如果 修改tuple :

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

遍历元组
dimensions = (200, 50)
for dimension in dimensions:
    print(dimension)
修改元组变量

虽然不能修改元组的元素 ,但可以给存储元组的变量赋值。

因此,如果要修改前述矩形的尺寸,可重新定义整个元组。

dimensions = (200, 50)
print("Original dimensions: ")
for dimension in dimensions:
    print(dimension)
    
dimensions = (400, 100)
print("\nModified dimensions: ")
for dimension in dimensions:
    print(dimension)
    
# 将一个新元组存储到变量 dimensions中 ,这次python不会报告任何错误,因为给元组变量赋值是合法的

字典

在python中,字典是一系列键值对 ,每个键都与一个值相关联 ,你可以使用键来访问与之关联的值 。与键相关联的值可以是数字、字符串、列表乃至字典 。事实上,可将任何python对象用作字典中的值 。

字典用放在 {} 中的一系列键值对表示 。键和值之间用冒号分隔 ,而键值对之间用逗号分隔 。在字典中 ,你想存储多少个键值对都可以 。

alien_0 = {'color': 'green', 'points': 5}

print(alien_0['color'])
print(alien_0['points'])

基本操作

添加键值对

依次指定字典名、键名 和相关联的值

alien_0['x_position'] = 0
alien_0['y_position'] = 25

print(alien_0)

修改字典中的值

alien_0 = {'color': 'green'}
alien_0['color'] = 'yellow'
alien_0 = {'x_position': 0, 'y_posiiton': 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
elif alien_0['speed'] == 'fast':
    x_increment = 3

alien_0['x_position'] = alien_0['x_position'] + x_increment

print("New x-position: " + str(alien_0['x_position']))

删除键值对

对于字典中不再需要的信息,可使用 del语句将相应的键值对彻底删除 。

使用del语句时,需要指定字典名和要删除的键

alien_0 = {'color': 'green', 'points': 5}

del alien_0['points']

由类似对象组成的字典

使用字典来存储众多对象的同一种信息

favourite_languages = {
    'jen': 'python',
    'sarah': 'c'
    'edward': 'ruby'
    'phil': 'python',   
}

print("Sarah's favourite language is "+
      favourite_languages['sarah'].title()
     +"." ) # 学习如何将较长的print内容拆分为多行

遍历字典

可遍历字典的所有键值对、键或值

遍历所有的键值对

方法 items() 返回一个键值对列表

user_0 = {
    'username': 'efermi',
    'first': 'enrico',
    'last': 'fermi', 
}


for key, value in user_0.items():
    print("Key: " + key)
    print("Value: " + value + "\n")

要编写用于遍历字典的for循环 ,可声明两个变量, 用于存储键值对中的键和值 。(这两个变量可使用任何名称)for k,v in user_0.items()

for 语句的第二部分包含字典名和方法 items() , 它返回一个键值对列表。

  • 注意:即便遍历字典时 ,键值对的返回顺序也与存储顺序不同。 python不关心键值对的存储顺序,而只跟踪键和值之间的关联关系

favourite_languages 中,字典存储的是不同人的同一种信息;对于类似这样的字典,遍历所有的键值对很合适。

favourite_languages = {
    'jen': 'python',
    'sarah': 'c'
    'edward': 'ruby'
    'phil': 'python',   
}
for name, language in favourite_language.items():
    print(name.title() + "'s favourite language is "+ language.title() + ".")

遍历字典中的所有键

在不需要使用字典中的值时, 方法 keys() 很有用 . keys() 返回一个列表,其中包含字典中所有的键

friends = ['phil', 'sarah']

for name in favourite_languages.keys():
    print(name.title())
    
    if name in friends:
        print(" Hi " + name.title() + 
              ", I see your favourite language is " +
             favourite_languages[name].title() + "!")
  • 遍历字典时,会默认遍历所有的键,因此如果将上述代码中的 for name in favourite_languages,keys(): 替换为 for name in favourite_languages: 输出不变

    如果显式地使用方法 keys() 可让代码更容易理解,你可以选择这样做 ,但如果你愿意,也可以省略它 。

获取字典的元素时,获取顺序是不可预测的。要以特定的顺序返回元素,一种方法是在for循环中对返回的键进行排序。为此,可使用函数 sorted()获得按特定顺序排列的键列表的副本。

for name in sorted(favourite_languages.keys()):
    print(name.title() + ", thank you for taking the poll")

遍历字典中的所有值

方法 values() 返回一个值列表,而不包含任何键 。

print("The following languages have been mentioned:")
for language in favourite_languages.values():
    print(language.title())

为剔除重复项,可使用集合set集合类似于列表,但每个元素都必须是独一无二的

for language in set(favourite_languages.values())

# 通过对包含重复元素的列表调用set(), 可让python找出列表中独一无二的元素,并使用这些元素来创建一个集合。

嵌套

有时候需要将一系列字典存储在列表中,或将列表作为值存储在字典中,这称为嵌套。

字典列表

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)

用代码自动生成外星人

aliens = []

for alien_number in range(30):
    new_alien = {'color': 'green', 'points': 5, 'speed': 'slow'}
    aliens.append(new_alien)

for alien in aliens[:5]:
    print(alien)
print("...")
   
print("Total number of aliens: " + str(len(aliens)))

"""
这些外星人具有相同的特征,但在python看来,每个外星人都是独立的 ,这让我们能够独立地修改每个外星人。
在什么情况下需要处理成群结队的外星人呢? 想象一下,可能随着游戏的进行,有些外星人会变色且移动速度会加快 。必要时,我们可以使用 for循环和 if语句来修改某些外星人的颜色 。
"""

for alien in aliens[0:3]:
    if alien['color'] == 'green':
        alien['color'] = 'yellow'
        alien['speed'] = 'medium'
        alien['points'] = 10

在字典中存储列表

pizza = {
    'crust': 'thick',
    'topping': ['mushrooms', 'extra cheese'], 
}

print("You ordered a " + pizza['crust'] + "-crust pizza" +
     "with the following toppings: ")

for topping in pizza['toppings'] :
    print("\t" + topping)
favourite_languages = {
    'jen': ['python', 'ruby'],
    'sarah': ['c'],
    'edward': ['ruby', 'go'],
    'phil': ['python', 'haskell'],
}

for name, languages in favourite_languages.items():
    print("\n" + name.title() + "'s favourite languages are :")
    for language in languages:
        print("\t" + language.title())

在字典中存储字典

如果有多个网站用户 ,每个都有独特的用户名,可在字典中将用户名作为键 ,然后将每位用户的信息存储在一个字典中 ,并将该字典作为与用户相关联的值 。

users = {
    'asinstein': {
        'fisrt': 'albert',
        'last': 'einstein',
        'location': 'princeton',
    }
    
    'mcurie': {
        'first': 'marie',
        'last': 'curie', 
        'location': 'paris',
    }
    
}

for username, user_info in users.items() :
    print("\nusername: " + username)
    full_name = user_info['first'] + " " + user_info['last']
    location = user_info['location']
    
    print("\tFull name: " + full_name.title())
    print("\tLocation: " + location.title())
    

if 语句

cars = ['audi', 'bmw', 'subaru', 'toyota']

for car in cars:
    if car == 'bmw':
        print(car.upper())
    else:
        print(car.title())

条件测试

python 中检查是否相等时区分大小写

car = 'Audi'
if car.lower == 'audi':
    print("Yes")

检查多个条件

关键字 and 和 or

age_0 = 22
age_2 = 18
if age_0>=21 and age_1 >=21 :
    print("Yes")

检查特定值是否包含在列表中

要判断特定的值是否已经包含在列表中,可使用关键字 in

requested_toppings = ['mushrooms', 'onions', 'pineapple']
if 'mushrooms' in requested_toppings:
    print("True")

关键字 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 .")

布尔表达式

布尔值通常用于记录条件,如游戏是否正在运行,或用户是否可以编辑网站的特定内容

game_active = True
can_edit = False

在跟踪程序状态或程序中重要的条件方面,布尔值提供了一种高效的方式。

语句

if-else 语句

if-elif-else 语句

检查超过两个的情形 。python只执行 if-elif-else 结构中的一个代码块,遇到测试通过时,跳过余下的测试

age = 12

if age < 4:
    print('Your admission cost is $0')
elif age < 18:
    print('Your admission cost is $5')
else :
    print("Your admission cost is $10")

better:

age = 12

if age<4:
    price = 0
elif age < 18 :
    price = 5
else :
    price = 10
    
print("Your admission cost is $" + str(price) + ".")

省略 else 代码块

else 的特性可能会引入无效甚至恶意的数据。如果知道最终要测试的条件,应考虑使用一个 elif 代码块来代替else 代码块

测试多个条件

requested_toppings = ['mushrooms', 'extra cheese']

if 'mushrooms' in requested_toppings :
    print("Adding mushrooms")   
if 'pepperoni' in requested_toppings :
    print("Adding pepperoni")
if 'extra cheese' in requested_toppings:
    print("Adding extra cheese")
   
print("\nFinished making your pizza!")

if 语句处理列表

requested_toppings = ['mushrooms', 'green peppers', 'extra cheese']

for requested_topping in requested_toppings:
    if requested_topping == 'green peppers' :
        print("Sorry, we are out of green peppers right now") 
    else:
        print("Adding" + requested_topping + ".")

确定列表不是空的

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?")

使用多个列表

avaliable_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 + ".")

用户输入

函数input()

函数 input() 让程序暂停运行,等待用户输入一些文本 。获取用户输入后 ,python将其存储在一个变量中,以方便你使用。

函数 input() 接收一个参数 :即要向用户显示的提示或说明,让用户知道该如何做 。

message = input("Tell me something, and I will repeat it back to you: ")
print(message)

"""
python 在运行第1行代码时 ,用户将看到提示 :Tell me something, and I will repeat it back to you: , 程序等待用户输入 ,并在用户按回车键后继续运行 。
输入存储在变量 message中 ,接下来 print(message) 将输入呈现给用户 。
"""

使用 int() 来获取数值输入

使用 input() 时,python将用户输入解读为字符串 。

height = input("How tall are you, in inches?")
height = int(height)

if height >= 36:
    print("\nYou are tall enough to ride !")
else :
    print("\nYOu'll be able to ride when you're a little older.")

while循环

current_number = 1
while current_number <= 5:
    print(current_number)
    current_number += 1

可使用while循环让程序在用户愿意时不断地运行

prompt = "\nTell me something, and I will repeat it back to you:"
prompt += "\nEnter 'quit' to end the programe. "

message = ""
while message != 'quit' :
    message = input(prompt)
    if message != 'quit' :
    	print(message)

使用标志

导致程序结束的事件有很多时,如果在一条 while语句中检查所有这些条件,将既复杂又困难

在要求很多条件都满足才继续运行的程序中,可定义一个变量 ,用于判断整个程序是否处于活动状态。这个变量被称为标志

这样在while语句中就只需检查一个条件,并将所有测试都放在其他地方

active = True
while active:
    message = input(prompt)
    
    if message == 'quit':
        active = False
    else:
        print(message)
        
# 简化了while语句,因为不需要在其中做任何比较 —— 相关的逻辑由程序的其他部分处理

break退出循环

prompt = "\nPlease enter the name of a city you have visited: "
prompt+= "\n(Enter 'quit' when you are finished.)"

while True:
    city = input(prompt)
    if city == 'quit':
        break
    else:
        print("I'd love to go to " + city.title())

循环中使用 continue

continue 回到循环开头,并根据条件测试结果决定是否继续执行循环

current_number = 0
while current_number < 10:
    current_number += 1 
    if current_number % 2 ==0 :
        continue
    print(current_number)

while循环处理列表和字典

unconfirmed_users = ['alice', 'brian', 'candace']
confirmed_users = []

while unconfirmed_users :
    current_user = unconfirmed_users.pop()
    #函数 pop()从列表末尾删除元素
    print("Verifying user: " + current_user.title())
    confirmed_users.append(current_user)
    
print("\nThe following users have been confirmed:")
for confirmed_user in confirmed_users:
    print(confirmed_user.title())
    
删除包含特定值的所有列表元素

函数 remove() 删除特定值但只删除第一次出现的该值

pets = ['dog', 'cat', 'dog', 'goldfish', 'cat', 'rabbit', 'cat']

while 'cat' in pets:
    pets.remove('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+ ".")

函数

格式

给形参指定默认值时,等号两边不要有空格 ,对于函数调用中的关键值实参同理。

参数过长时:

def function_name(
		parameter_0, parameter_1, parameter_2, parameter_3)
	function body

定义函数

def greet_user(username): #函数定义
    print("Hello," + username.title() + "!")
    
greet_user('jesse') #函数调用

关键字def告诉python你要定义一个函数。这是函数定义,向python指出了函数名,还可能在括号内指出函数为完成其任务需要什么样的信息。

传递实参

向函数传递实参的方法:

可使用位置实参,这要求实参的顺序和形参的顺序相同;也可使用关键字实参,其中每个实参都由变量名和值组成;还可使用列表和字典

位置实参

函数调用中的每个实参关联到函数定义中的一个形参。为此最简单的关联方法是基于实参的顺序。这种关联方式被称为位置实参

def describe_pet(animal_type, pet_name):
    """显示宠物的信息"""
    print("\nI have a " + animal_type + ".")
    print("My " + animal_type + "'s name is " + pet_name.title() + ".")
    
describe_pet('hamster', 'harry')
describe_pet('dog', 'willie')

关键字实参

关键字实参是传递给函数的 名称-值 对。你直接在实参中将名称和值关联起来了。

describe_pet(animal_type='hamster', pet_name='harry')
describe_pet(pet_name='harry', animal_type='hamster')

默认值

编写函数时,可给每个形参指定默认值。

在调用函数时给形参提供了实参时,python将使用指定的实参值;否则,将使用形参的默认值 。

def describe_pet(pet_name, animal_type = 'dog'):
    print("\nI have a " + animal_type + ".")
    
describe_pet(pet_name='willie')

使用默认值时 ,在形参列表中必须先列出没有默认值的形参,再列出有默认值的实参。这让python依然能够正确地解读位置实参。

让实参变成可选的

让实参变成可选的这样使用函数的人就只需要在必要时才提供额外的信息。可使用默认值来让实参变成可选的。

def get_formatted_name(first_name,  last_name, middle_name=''):
    """返回整洁的姓名"""
    if middle_name:
    	full_name = first_name + ' ' +last_name
    else:
        full
    return full_name.title()

musician = get_formatted_name('jimi','hendrix')
print(musician)

传递任意数量的实参

python允许函数从调用语句中收集任意数量的实参。

def make_pizza(*toppings):
    print("\nMaking a pizza with the following toppings:")
    for topping in toppings:
        print("-" + topping)

make_pizza('pepperoni')
make_pizza('mushrooms', 'green peppers', 'extra cheese')

形参名 *toppings 中的星号让python创建一个名为toppings的空元组,并将收到的所有值都封装到这个元组中。

结合使用位置实参和任意数量实参

如果要让函数接受不同类型的实参,必须在函数定义中将接纳任意数量实参的形参放在最后。

python先匹配位置实参和关键字实参,再将余下的实参都收集到最后一个形参中。

def make_pizza(size, *toppings):
    print("\nMaking a "+ str(size) + "-inch pizza with the following toppings:")
    for topping in toppings:
        print("- "+ topping)
make_pizza(16, 'pepperoni')
make_pizza(12, 'mushrooms', 'green peppers', 'extra cheese')
使用任意数量的关键字实参

有时候,需要接收任意数量的实参,但预先不知道传给函数的会是什么样的信息。在这种情况下,可将函数编写成能够接受任意数量的键值对

Example:创建用户简介,你知道将收到有关用户的信息,但不确定会是什么样的信息。

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)

形参 **user_info 中的两个星号让python创建一个名为 user_info 的空字典,并将收到的所有 名称- 值对都封装到这个字典中。

传递列表

def greet_users(names):
    """向列表中的每位用户都发出简单的问候"""
    for name in names:
        msg = "Hello" + name.title() + "!"
        print(msg)
        
usernames = ['hannah', 'ty', 'margot']
greet_users(usernames)        
在函数中修改列表

在函数中对列表所做的任何修改都是永久性的

在不使用函数的情况下:

unprinted_designs = ['iphone case', 'robot pendant', 'dodecahedron']
completed_models = []

while unprinted_designs:
    current_model = unprinted_designs.pop()
    print("Printing model: "+ current_design)
    completed_models.append(current_model)
    
print("\nThe following models have been printed:")
for completed_model in completed_models:
    print(completed_model)

为重新组织这些代码,我们可编写两个函数,每个都做一件具体的工作。第一个函数将负责处理打印设计的工作,而第二个将概述打印了哪些设计

def print_models(unprinted_designs, completed_models):
    """
    模拟打印每个设计,直到没有未打印的设计为止
    """
    while unprinted_designs:
        current_design = unprinted_designs.pop()
        completed_designs.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)
禁止函数修改列表

向函数传递列表的副本而不是原件,这样函数所做的任何修改都只影响副本,而不影响原件。

function_name(list_name[:])

切片表示法[:] 创建列表的副本。

虽然向函数传递列表的副本可保留原始列表的内容,但除非有充分的理由需要传递副本,否则还是应该将原始列表传递给函数,可避免花时间和内存创建副本,从而提高效率

返回值

返回简单值

def get_formatted_name(first_name, last_name):
    """返回整洁的姓名"""
    full_name = first_name + ' ' +last_name
    return full_name.title()

musician = get_formatted_name('jimi','hendrix')
print(musician)

返回字典

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')

结合使用函数和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 = inpu("Last name: ")
     if f_name == 'q':
        break
        
    formatted_name = get_formatted_name(f_name, l_name)
    print("\nHello, "+ formatted_name + "!")

将函数存储在模块中

将函数存储在被称为模块的独立文件中,再将模块导入到主程序中。 import语句允许在当前运行的程序文件中使用模块中的代码

模块pizza.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 所在的目录中创建一个名为 making_pizzas.py 的文件, 这个文件导入刚创建的模块,再调用make_pizza()

import pizza

pizza.make_pizza(16, 'pepperoni')
pizza.make_pizza(12, 'mushrooms', 'green peppers', 'extra cheese')

python 读取这个文件时,代码行 import pizza让python 打开文件 pizza.py , 并将其中的所有函数都复制到这个程序中

你看不到复制的代码,因为这个程序运行时,python在幕后复制这些代码。

指定导入模块的名称和函数名来调用被导入的模块中的函数

module_name.function_name()

导入特定函数

若导入特定函数,调用函数时就无需使用句点。由于在import语句中显式地导入了函数 , 因此调用它时只需指定其名称,而不用指定模块名

#通过逗号分隔函数名,可根据需要从模块中导入任意数量的函数
from module_name import function_0, function_1, function_2
from pizza import make_pizza

make_pizza(16, 'pepperoni')
make_pizza(12, 'mushrooms', 'green peppers', 'extra cheese')

使用 as 给函数指定别名

如果要导入的函数的名称可能与程序中现有的名称冲突,或者函数的名称太长,可指定别名。

from module_name import function_name as fn
from pizza import make_pizza as mp

mp(16, 'pepperoni')
mp(12, 'mushrooms', 'green peppers', 'extra cheese')

使用as给模块指定别名

通过给模块指定简短的别名,让你能够更轻松地调用模块中的函数。这样不仅能使代码更简洁,还可以让你不再关注模块名,而专注于描述性的函数名。

import module_name as mn

导入模块中的所有函数

使用 * 运算符可让python导入模块中的所有函数

由于导入了所有函数,可通过名称来调用每个函数,而无需使用句点表示法。

from module_name import *

然而,使用并非自己编写的大型模块时,最好不要采用这种方法: 如果模块中有函数的名称与你的项目中使用的名称相同,可能导致意向不到的结果:python可能遇到多个相同名称的函数或变量,进而覆盖函数,而不是分别导入所有的函数

规范

我们通常可以认为首字母大写的名称指的是类,而小写的名称指的是根据类创建的实例。

  • 类名应采用驼峰命名法,即将类名中的每个单词的首字母都大写,而不使用下划线。实例名和模块名都采用小写格式,并在单词之间加上下划线
  • 类中使用一个空行来分隔方法;而在模块中,使用两个空行来分隔类。
class Dog():#这个类定义中的括号是空的,因为我们要从空白创建这个类。
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def sit(self):
        print(self.name.title() + " s now sitting .")
        
    def roll_over(self):
        print(self.name.title() + " rolled over!")
        

实参 self

  • 实参self : 所有与类相关联的方法调用都自动传递实参 self ,它是一个指向实例本身的引用 ,让实例能够访问类中的属性和方法。

    • 以self为前缀的变量都可供类中的所有方法使用,
    • self.name = name 获取存储在形参name中的值,并将其存储到变量name中 ,然后该变量被关联到当前创建的实例

根据类创建实例

可将类视为有关如何创建实例的说明。

my_dog = Dog('willie', 6) **使用实参调用Dog类中的方法 _init_() ** ,方法 _init_() 并未显式地包含return语句,但python自动返回一个表示这条小狗的实例

属性

属性 : 可通过实例访问的变量

. 访问实例的属性

my_dog.name ,在这里,python先找到实例 my_dog, 再查找与这个实例相关联的属性name 。

调用方法

my_dog.sit()
my_dog.roll_over()

方法 __init__()

类中的函数称为方法

__init__()是一个特殊的方法,每当你根据Dog 类创建新实例时,python都会自动运行它

__init__()定义中,形参self必不可少,且须位于其他形参前。

python调用 __init__() 来创建Dog实例时,将自动传入实参self ,因此通过 实参向Dog()传递name和age ,self 会自动传递 ,我们不需要传递它。每个与类相关联的方法调用都自动传递实参 self ,它是一个指向实例本身的引用 ,让实例能够访问类中的属性和方法。

给属性指定默认值

类中的每个属性都必须有初始值,哪怕这个值是0或空字符串。

在有些情况下,如设置默认值时,在方法 __init__()内指定这种初始值是可行的;如果你对某个属性这样做了 ,就无需包含为它提供初始值的形参。

修改属性的值

修改属性的值的两种方法:直接通过实例进行修改;通过方法进行设置

class Car():
    def __init__(self, make, model, year):
        """初始化描述汽车的属性"""
        self.make = make
        self.model = model
        self.year = year
        self.odometer_reading = 0
        
	def get_descriptive_name(self):
        long_name = str(self.year) + ' ' + self.make + ' ' + self.model
        return long_name.title()
    
    def read_odometer(self):
        print("This car has " + str(self.odometer_reading) + " miles on it.")
    
    
my_new_car = Car('audi', 'a4', 2016)
print(my_new_car.get_descriptive_name())
my_new_car.read_odometer()
  1. 直接修改属性的值
my_new_car.odometer_reading = 23
my_new_car.read_odometer()
  1. 通过方法修改属性的值

这样就无需直接访问属性,而可将值传递给一个方法,由它在内部进行更新

class Car():
    --snip--
    
    def update_odometer(self, mileage):
        if mileage >= self.odometer_reading:
            self.odometer_reading = mileage
        else:
            print("You can't roll back an odometer!")
       
my_new_car.update_odometer(23)
my_new_car.read_odometer()

通过方法对属性的值进行递增

class Car():
    --snip--
    
    def update_odometer(self, mileage):
        --snip--
        
    def increment_odometer(self, miles):
        self.odometer_reading += miles

my_userd_car = Car('subaru', 'outback', 2013)

my_used_car.increment_odometer(100)

继承

一个类继承另一个类时,它将自动获取另一个类的所有属性和方法;原有的类称为父类,而新类称为子类。

子类继承了父类的所有属性和方法,同时还可以定义自己的属性和方法。

子类的方法

__init__()

创建子类的实例时,python首先要给继承自父类的所有属性赋值。

class Car():
	--snip--
    
    

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())
  • 父类必须包含在当前文件中,且位于子类前。
  • super() 函数:将父类和子类关联起来。super() 调用父类的方法 __init__() , 让ElectricCar 实例包含父类的所有属性 。父类也称为超类( superclass ) , 名称super因此得名
给子类定义属性和方法
class Car():
    --snip--
    
class ElectricCar(Car):
    """Represent aspects of a car, specific to electric vehicles"""
    
    def __init__(self, make, model, year):
        super.__init__(make, model, year)
        self.battery_size = 70
        
    def describe_battery(self):
        print("This car has a " + str(self.battery_size) + "-KWH battery.")        
重写父类的方法

对于父类的方法,只要它不符合子类模拟的实物的行为,都可对其进行重写。为此,可在子类中定义一个与要重写的父类的方法重名的方法。

def ElectronicCar(Car):
    --snip--
# 假设Car类有一个fill_gas_tank的方法,它对全电动汽车来说毫无意义    
    def fill_gas_tank():
        print("This car doesn't need a gas tank!")
# 如果有人要对电动汽车调用方法 fill_gas_tank,python将忽略Car类中的方法,转而运行上述代码

将实例用作属性

将大型类拆分成多个协同工作的小类。

例如,不断给 ElectricCar 类添加细节时,我们可能会发现其中包含很多专门针对汽车电瓶的属性和方法,我们可将这些属性和方法提取出来,放到另一个名为 Battery 的类中,并将一个 Battery 实例作为 ElectricCar 类的一个属性

class Car():
    --snip--
    
class Battery():
    def __init__(self, battery_size=70):
        self.battery_size = battery_size
        
    def describe_battery(self):
        print("This car has a " + str(self.battery_size) + "-KWh battery.")
        
    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_tesla = ElectricCar('tesla', 'model s', 2016)

print(my_tesla.get_descriptive_name())
my_tesla.battery.describe_battery()
my_tesla.battery.get_range()

导入类

将类存储在模块中,然后在主程序中导入所需的模块

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 Battery():
    def __init__(self, battery_size=70):
        self.battery_size = battery_size
        
    def describe_battery(self):
        print("This car has a " + str(self.battery_size) + "-KWh battery.")
        
    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()

导入多个类

import 语句让python打开模块并导入类

from module_name import class_name

my_car.py

from car import Car, ElectricCar
my_new_car = Car('audi', 'a4', 2016)#创建实例

导入整个模块

使用 module_name.class_name 访问需要的类

导入整个模块,再使用句点表示法访问需要的类。由于创建类实例的代码都包含模块名,因此不会与当前文件使用的任何名称发生冲突

import car

my_beetel = car.Car('volkswagen', 'beetle', 2016)

my_tesla = car.ElectricCar('tesla', 'roadster', 2016)

python标准库

python标准库是一组模块,安装的python都包含它 。

OrderedDict 类

字典让你能够将信息关联起来,但它们不记录你添加键值对的顺序。要创建字典并记录其中的键值对的添加顺序,可使用模块 collections 中的 OrderedDict 类

from collections import OrderedDict

favourite_languages = OrderedDict()

favourite_languages['jen'] = 'python'
favourite_languages['sarah'] = 'c'
favourite_languages['edward'] = 'ruby'
favourite_languages['phil'] = 'python'

for name, language in favourite_languages.items():
    print(name.title() + "'s favourite language is " + language.title() + ".")

模块 random

模块 random 包含以各种方式生成随机数的函数,其中的 randint() 返回一个位于指定范围内的整数

from random import randint
x = randint(1,6)

文件和异常

从文件中读取数据

读取整个文件

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() : 要以任何方式使用文件,都得先打开文件,这样才能访问它。函数open() 接受一个参数:要打开的文件的名称。 python在当前执行的文件所在的目录中查找指定的文件。open() 返回一个表示文件的对象。

  • 关键字 with在不再需要访问文件后将其关闭。你也可以调用open() 和close() 来打开和关闭文件,但这样做时如果程序存在bug,导致close()语句未执行,文件将不会关闭。

  • 方法 read() 读取这个文件的全部内容,并将其作为一个长字符串存储在变量 contents 中

  • 相比于原始文件,该输出唯一不同的地方是末尾多了一个空行。因为 read()到达文件末尾时返回一个空字符串,而将这个空字符串显示出来时就是一个空行。要删除多出来的空行,可在print语句中使用 rstrip() : , rstrip() 删除字符串末尾的空白

print(contents.rstrip())

文件路径

windows系统中 文件路径中使用 \ 而不是 /

相对路径:相对于当前运行的程序所在的目录

逐行读取

要以每次一行的方式检查文件,可对文件对象使用 for循环。

filename = 'pi_digits.txt'

with open(filename) as file_object:
    for line in file_object:
        print(line.rstrip())
        
# 若无 rstrip() , 每行都会多出一个空白行。因为这个文件中,每行的末尾都有一个看不见的换行符,而print语句也会加上一个换行符,因此每行末尾都有两个换行符: 一个来自文件,另一个来自 print语句

创建一个包含文件各行内容的列表

使用关键字with时,open() 返回的文件对象只在 with代码块内可用。

如果要在with代码块外访问文件的内容 ,可在with代码块内将文件的各行存储在一个列表中,并在with代码块外使用该列表 。

filename = 'pi_digits.txt'

with open(filename) as file_object:
    lines = file_object.readline()

pi_string = ''
for line in lines:
    pi.string += line.strip()
  • 读取文本文件时,python将其中的所有文本都解读为字符串。如果你读取的是数字并要将其作为数值使用 ,就必须使用函数 int() 将其转换为整数 ,

写入文件

写入空文件

要将文本写入文件,你在调用 open() 时需要提供另一个实参 ,告诉python你要写入打开的文件。

filename = 'programming.txt'

with open(filename, 'w') as file_object:
    file_objcect.write("I love programming.")

# python只能将字符串写入文本文件。要将数值数据存储到文本文件中,必须先使用函数str() 将其转换为字符串格式

"""
调用 open() 时提供了两个实参 。第一个实参是要打开的文件的名称; 第二个实参 'w' 告诉python要以写入模式打开这个文件
'r' : 读取模式
'w' : 写入模式
'a' : 附加模式
'r+' : 读取和写入文件
如果你省略了模式实参,python将以默认的只读模式打开文件。
""" 

如果你要写入的文件不存在,函数 open() 将自动创建它。然而 ,以写入 (‘w’) 模式打开文件时注意 :如果指定的文件已经存在,python将在返回文件对象前清空该文件

写入多行

函数 write() 不会在你写入的文本末尾添加换行符 ,因此如果你写入多行时没有指定换行符,文件看起来可能不是你希望的那样

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.\n")

附加到文件

如果你要给文件添加内容,而不是覆盖原有的内容,可以附加模式打开文件。

以附加模式打开文件时,你写入到文件的行都将添加到文件末尾。如果指定的文件不存在,python将为你创建一个空文件。

附加模式 : ‘a’

异常

python使用被称为异常的特殊对象来管理程序执行期间发生的错误。每当发生让python不知所措的错误时,它都会创建一个异常对象。

如果你编写了处理该异常的代码,程序将继续运行如果你未对异常进行处理,程序将停止,并显示一个 traceback , 其中包含有关异常的报告

异常使用 try-except 代码块处理 。try-except 代码块让python执行指定的操作,同时告诉python发生异常时怎么办。使用了 try-except 代码块时,即便出现异常,程序也将继续运行:显示你编写的友好的错误消息,而不是 traceback 。

让用户看到traceback不是好主意,用户可能通过 traceback获悉你不希望他知道的信息。例如他将知道你的程序文件的名称,还将看到部分不能正确运行的代码。

使用异常避免崩溃

发生错误时,如果程序还有工作没有完成,妥善地处理错误就尤其重要。这种情况经常会出现在要求用户提供输入的程序中:如果程序能够妥善地处理无效输入,就能再提示用户提供有效输入,而不至于崩溃。

print("Give me two numbers, and I'll divide them")
print("Enter 'q' to quit.")

while True:
    first_number = input("\nFirst number: ")
    if first_number == 'q':
        break
    second_number = input("Second number:")
    if second_number == 'q':
        break
        
    answer = int(first_number) / int(second_number)

该程序没有才去任何处理错误的措施,因此让它执行 除数为0的除法运算时,它将崩溃。

通过将可能引发错误的代码放在 try-except 代码块中,可提高这个程序抵御错误的能力。

print("Give me two numbers, and I'll divide them")
print("Enter 'q' to quit.")

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)

依赖于 try代码块成功执行的代码都放在 else代码块中

try-except-else 代码块的工作原理:python尝试执行try代码块中的代码;只有可能引发异常的代码才需要放在try语句中。

若try代码块成功执行:执行else代码块。

若运行try代码块引发了指定异常: 则执行except代码块

ZeroDivisionError异常

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

使用 try-except 代码块

try:
    print(5/0)
except ZeroDivisionError:
    print("You can't divide by zero!")

#如果try 代码块中的代码运行起来没有问题,python将跳过except代码块;如果try代码块中的代码导致了错误,python将查找这样的except代码块,并运行其中的代码

FileNotFoundError 异常

filename = 'alice.txt'

try:
	with open(filename) as f_obj:
    	contents = f_obj.read()
except FileNotFoundError:
    msg = "Sorry, the file " + filename + "does not exist."

else:
    # 计算文件大致包含多少个单词
    words = contents.split()
    num_words = words.len()
    print("The file " + filename " has about "+ str(num_words) + " words")
def count_words(filename):
    try:
		with open(filename) as f_obj:
    		contents = f_obj.read()
	except FileNotFoundError:
    	msg = "Sorry, the file " + filename + "does not exist."

	else:
   	 	# 计算文件大致包含多少个单词
    	words = contents.split()
    	num_words = words.len()
    	print("The file " + filename " has about "+ str(num_words) + " words")
        
        filenames = ['alicetxt', 'siddhartha,txt', 'little_women.txt']
        for filename in filenames:
            count_words(filename)

两个优点:

1.避免用户看到traceback

2.让程序能够继续分析其他文件( 若中途出现找不到文件的情况, 引发FileNotFoundError 异常后程序停止运行)

失败时一声不吭

并非每次捕获到异常时都需要告诉用户。python有一个pass语句,可在代码块中使用它来让python什么都不要做

try:
    --snip--
except FileNotFoundError:
    pass
else:
    --snip--

存储数据

程序把用户提供的信息存储在列表和字典等数据结构中。用户关闭程序时,你几乎总是要保存他们提供的信息 : 一种简单的方式是使用模块json来存储数据

模块json让你能够将简单的python数据结构转储到文件中,并在程序再次运行时加载该文件中的数据。

JSON : JavaScript Object Notation 格式最初是为 JavaScript开发的,随后成立一种常见格式,被包括python在内的众多语言采用

json.dump() json.load()

number.josn

import json

numbers = [2, 3, 5, 7, 11, 13]

filename = 'numbers.json'
with open(filename, 'w') as f_obj:
    json.dump(numbers, f_obj)
    
#json.dump() 接收两个实参:要存储的数据以及可用于存储数据的文件对象
import json

filename = 'number.json'
with open(filename) as f_obj:
    numbers = json.load(f_obj)
# open 函数默认以只读方式打开文件    
print(numbers)

保存和读取用户生成的数据

remember_me.py

import json

username = input("What is your name? ")

filename = 'username.josn'
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.josn'

with open(filename) as f_obj:
    username = json.load(f_obj)
    print("Welcome back, " + username )
  • 将两个程序合并到一个程序 remember_me.py 中。 这个程序运行时,我们将尝试从文件 username.json 中获取用户名,因此我们首先编写一个尝试恢复用户名的try代码。
  • 如果这个文件不存在,我们就在except代码块中提示用户输入用户名 ,并将其存储在username.json 中

remember_me.py

import json

filename = 'username.json'
try:
    with open(filename) as f_obj:
    	username = json.load(f_obj)
except FileNotFoundError:
    username = input("What is your name?")
    with open(filename, 'w') as f_obj:
        json.dump(username, f_obj)
else:
    print("Welcome back, " + username)

重构 : 将代码划分为一系列完成具体工作的函数

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("...")
        with open(filename,'w') as f_obj:
            json.dump(username, f_obj)
            
def greet_user():
    username = get_stored_username()
    if username:
        print("...")
	 else:
        get_new_username()
            
    
greet_user()   

测试代码

python标准库中的模块 unittest 提供了代码测试工具。

#6个常用的断言方法:

assertEqual(a, b)	#核实 a == b
assertNotEqual(a, b)	#核实 a != b

assertTrue(x)	#核实 x 为 True
assertFalse(x)

assertIn(item, list)	#核实 item在list中
assertNotIn(item, list)

测试函数

单元测试用于核实函数的某个方面没有问题; 测试用例是一组单元测试,这些单元测试一起核实函数在各种情况下的行为、都符合要求。

name_function.py

def get_formatted_name(first, last):
    formatted_name = first.title() + ' ' + last.title()
    return formatted_name

test_name_function.py

import unittest
from name_function import get_formatted_name

class NamesTestCase(unittest.TestCase):
    #创建一个名为 NamesTestCase 的类,用于包含一系列针对 get_formatted_name 的单元测试
    """ 测试 name_function.py """
    def test_first_last_name(self):
    	formatted_name = get_formatted_name('janis', 'joplin')
    	self.assertEqual(formatted_name, 'Janis Joplin')
    
unittest.main()
  • 创建的类必须继承 unittest.TestCase 类, 这样ypthon才知道如何运行你编写的测试

  • 运行 test_name_function 时,所有以 _test 打头的方法都将自动运行

  • unittest 类最有用的功能之一:一个断言方法 。断言方法用来核实得到的结果是否和期望的结果一致

.
----------------------------------------------------------------------
Ran 1 test in 0.000s

OK

# 第一行的 . 表明有一个测试通过了,接下来的一行指出python运行了一个测试,消耗的时间不到 0.001 秒, 最后的 OK 表明该测试用例的所有单元测试都通过了

不能通过的测试

name_function.py

def get_formatted_name(first, middle, last):
    full_name = first + ' ' + middle + ' ' + last
    return full_name

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

improve: 将middle变为可选参数

def get_formatted_name(first, last, middle=''): 
#注意默认参数需要放在参数列表的末尾,否则传参会默认按位置传参

测试类

survey.py

class AnonymousSurvey():
    """收集匿名调查问卷的答案"""
    def __init__(self):
        """存储一个问题,并未存储答案做准备"""
        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)
    
    

language_survey.py

from survey import AnonymousSurvey

question = "What language did you first learn to speak ? "
my_survey = AnonyousSurvey(question)
#隐式调用 class AnonyousSurvey 的构造函数 __init__ , 自动传递参数 self ,以及形参 question

my_survey.show_question()
print("Enter 'q' at any time to quit.\n")
while True:
    response = input("Language: ")
    if response == 'q':
        break
    my_survey.store_response(response)
    
my_survey.show_results()

test_survey.py

import unittest
from survey import AnonymousSurvey

class TestAnonymousSurvey(unittest.TestCase):
    def test_store_single_response(self):
        question = "What language did you first learn to speak? "
        my_survey = AnonymousSurvey(question)
        my_survey.store_response('English')
        self.assertIn('English', my_survey.responses)
        
        
    def test_store_three_response(self):
        ...
        responses = ['English', 'Spanish', 'Mandarin']
        for response in responses:
            my_survey.store_response(response)
            
        for response in responses:
            self.assertIn(response, my_survey.responses)
        
unittest.main()

方法setUp()

上面的 test_survey.py中, 我们在每个测试方法中都创建了一个 AnonymousSurvey 实例,并在每个方法中都创建了 responses

unittest.TestCase 类包含方法 setUp() , 让我们只需要创建这些对象一次,并在每个测试方法中使用它们。

如果你在 TestCase 类中包含了方法 setUp() , python 将先运行它,再运行各个以 test_ 打头的方法。这样,在你编写的每个测试方法中都可使用在 setUp() 中创建的对象

import unittest
from survey import AnonymousSurvey

class TestAnonymousSurvey(unittest.TestCase):
    
    def SetUp(self):
        """创建一个question和 responses供测试方法使用"""
        question = "What languag 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.resonses[0])
            self.assertIn(self.response[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()

“”“收集匿名调查问卷的答案”“”
def init(self):
“”“存储一个问题,并未存储答案做准备”“”
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)



language_survey.py

```python
from survey import AnonymousSurvey

question = "What language did you first learn to speak ? "
my_survey = AnonyousSurvey(question)
#隐式调用 class AnonyousSurvey 的构造函数 __init__ , 自动传递参数 self ,以及形参 question

my_survey.show_question()
print("Enter 'q' at any time to quit.\n")
while True:
    response = input("Language: ")
    if response == 'q':
        break
    my_survey.store_response(response)
    
my_survey.show_results()

test_survey.py

import unittest
from survey import AnonymousSurvey

class TestAnonymousSurvey(unittest.TestCase):
    def test_store_single_response(self):
        question = "What language did you first learn to speak? "
        my_survey = AnonymousSurvey(question)
        my_survey.store_response('English')
        self.assertIn('English', my_survey.responses)
        
        
    def test_store_three_response(self):
        ...
        responses = ['English', 'Spanish', 'Mandarin']
        for response in responses:
            my_survey.store_response(response)
            
        for response in responses:
            self.assertIn(response, my_survey.responses)
        
unittest.main()

方法setUp()

上面的 test_survey.py中, 我们在每个测试方法中都创建了一个 AnonymousSurvey 实例,并在每个方法中都创建了 responses

unittest.TestCase 类包含方法 setUp() , 让我们只需要创建这些对象一次,并在每个测试方法中使用它们。

如果你在 TestCase 类中包含了方法 setUp() , python 将先运行它,再运行各个以 test_ 打头的方法。这样,在你编写的每个测试方法中都可使用在 setUp() 中创建的对象

import unittest
from survey import AnonymousSurvey

class TestAnonymousSurvey(unittest.TestCase):
    
    def SetUp(self):
        """创建一个question和 responses供测试方法使用"""
        question = "What languag 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.resonses[0])
            self.assertIn(self.response[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()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值