《Python编程从入门到实践》基础知识个人笔记 第2章 变量和简单数据类型 第3章 列表简介 第4章 操作列表 第5章 if语句 第6章 字典 第7章 用户输入和while循环 第8章 函数 第9章 类 第10章 文件和异常 第11章 测试代码
【美】Eric Matthes 2016年7月第1版
2.2 变量
2.2.1 变量的命名规则
- 变量名字只能包含字母、数字和下划线
- 且不能以数字开头
- 不能包含空格
- 不要使用内置关键字和函数名
- 变量名要见名识义
- 慎用小写字母l和大写字母O
2.3 字符串
2.3.1 使用方法修改字符串的大小写
-
title( )
以首写字母大写的方式显示每个单词
name = "peter"
print(name.title())
-
upper( )
将字符串改为全部大写 -
lower( )
将字符串改为全部小写
2.3.2 合并(拼接)字符串
- 可以直接使用
+
来合并字符串
2.3.3 使用制表符或换行符来添加空白
- 制表符
- 换行符
2.3.4 删除空白
-
strip( )
删除字符串开头和结尾多余的空白 -
ltrip( )
删除字符串开头多余的空白 -
rtrip( )
删除字符串结尾多余的空白
注意:这种删除只是暂时的,再次访问变量值时会恢复,要永久删除空白,必须删除操作过后存回变量中。
name = " peter "
name = name.strip()
第3章 列表简介
3.1 列表是什么
- 列表是一系列按特定顺序排列的元素组合
- 用方括号
[ ]
表示列表,并用逗号分隔其中的元素 - 通常用复数的名称命名,如
names,letters
3.1.1 访问列表元素
- 通过元素索引并将其放在方括号内(注意索引差一的特征)
print(list[0])
- 将索引指定为
-1
时,返回列表中最后一个元素
3.2.1 修改列表元素
- 指定列表名和要修改的元素索引,再赋予新值
name[0] = "Jack"
3.2.2 在列表中添加元素
-
append( )
在列表末尾添加元素name.append("Ken")
-
insert( )
在列表的指定位置添加新元素name.insert(0,"Mark")
3.2.3从列表中删除元素
1.使用del
语句删除元素(前提要知道删除元素的位置)
-
del name[0]
值从列表删除后无法再访问
2、使用方法pop( )
删除元素
- 该方法可以删除列表末尾的元素,并接着使用它的值(弹出)
name_pop = name.pop()
3、弹出列表中任何位置处的元素name_pop = name.pop(0)
注意:每当使用pop( )
时,被弹出的元素就不在该列表中了
4、根据值删除元素
-
remove( )
只有知道要删除元素的值时使用 - 使用
remove( )
从列表中删除元素时,也可以接着使用它的值
注意:方法remove( )
只删除第一个指定的值。如果要删除的值可能在列表中出现多次,就需要使用循环来判断是否删除了所有这样的值。
3.3 组织列表
3.3.1 使用方法sort()
对列表进行永久性排序
- 可以实现列表按字母顺序排列,传递参数
reverse = True
可以相反顺序排列元素name.sort(reverse = True)
3.3.2 使用函数sorted()
对列表进行临时排序
3.3.3 倒着打印列表
- 使用方法
reverse()
反转列表元素的排列顺序,name.reverse()
- 虽然也是永久性地修改列表元素的排列顺序,但可以随时再次调用
reverse()
恢复原来的排列顺序
3.3.4 确定列表的长度
-
len( )
函数可以快速获悉列表的长度(列表包含多少个元素)
第4章 操作列表
4.1 遍历(for循环)
4.3 创建数值列表
4.3.1 使用函数range( )
- 该函数有差一特征,要打印数字1~5,使用代码
range(1,6)
- 使用
range()
创建数字列表,并可以设置步长numnbers = list(range(2,11,2))
4.3.4 列表解析
- 列表解析将for循环和创建新元素的代码合并成一行,并自动附加新元素
squares = [value**2 for value in range(1,11)]
4.4 列表切片
- 差一行为:要输出列表中的前三个元素,需要指定索引0~3,分别输出为0,1和2的元素
numbers[0:3]
- 要提取列表的第2~4个元素,可将起始索引指定为1,终止索引指定为4
number[1:4]
- 若起始索引省略,代表从列表头开始
number[:3]
,同样终止索引也可以省略,代表到列表尾number[2:]
- 负数索引返回离列表末尾相应距离的元素,如输出最后三个元素
number[-3:]
- 复制列表,方法是同时省略起始索引和终止索引
number[:]
4.5 元组
- 不能修改的值称为不可变的,而不可变的列表被称为元组,使用圆括号
()
标识
4.5.3 修改元组变量
- 虽然不能修改元组的元素,但可以给存储元组的变量赋值,因为给元组变量赋值是合法的
demensions = (200,50)
demensions = (400,100)
4.6 设置代码格式
- Python改进提案(Python Enhancement Proposal,PEP),其中PEP8是最古老的PEP之一
- 代码行长建议不超过80字符,注释行长不超过72字符,不可逾越红线99字符
第5章 if语句
5.2 条件测试
- 检查是否相等用
==
,一个等号是陈述,两个等号是发问 - 检查是否相等时区分大小写
- 检查是否不相等用
=!
- 检查多个条件,
age >= 10 and age<= 21
- 检查特定值是否包含在列表中,使用关键字
in
,如'paul' in names
返回布尔值 - 检查特定值是否不包含在列表中,使用关键字
not in
5.3.3 if-elif-else语句
- 该语句只执行结构中的一个代码块,它依次检查每个条件测试,直到遇到通过了的条件测试
- 并不要求if-elif结构后面必须有else代码块
5.3.6 测试多个条件
- 当需要检查你关系的所有条件时,应使用一些列不包含elif和else代码块的简单if语句
5.4 使用if语句处理列表
- 检查特殊元素,先用for语句遍历,再用if语句判断元素具体情况
- 确定列表不为空,先用if语句判断列表是否为空,再if代码块中执行for循环,否则执行else代码块
- 使用多个列表,检查列表1中的元素是否在列表2中
list_1 = [1,2,3,4,5]
list_2 = [1,2,5,6,7]
for i in list_1:
if i in list_2:
print("yes")
else:
print("no")
第6章 字典
6.2 使用字典
- 用放在花括号
{}
中的一些列键-值对表示,如student = {"name":"paul","age":28}
- 可以利用字典的键名访问相关联的值,如
student['name']
- 指定字典名、用方括号括起来的键和相关联的值,添加键-值对,如
student[score] = 100
- 注意,键-值对的排列顺序与添加顺序不同,Python不关心键-值对的添加顺序,而只关心键和值之间的关联关系
- 使用字典来存储用户提供的数据或在编写自动生成大量键-值对的代码时,通常都需要先定义一个空字典
- 要修改字典的值,直接用原字典名和键名来重新赋值,如
student[score] = 99
- 要删除键-值对,可以使用
del
语句,但必须指定字典名和要删除的键,如del student["name"]
,删除的键-值对永远消失 - 使用较长的列表或字典时,使用以下格式设置方式:
student_score = {
"a":80,
"b":90,
"c":100,
}
6.3 遍历字典
- 有多种遍历字典的方式:可以遍历字典的所有键-值对,键或值
- ①遍历所有的键-值对,用
for key,value in student_score.items():
,注意,即便遍历字典时,键-值对的返回顺序也与存储顺序不同 - ②遍历字典中的所有键,用
for key in student_score.keys():
,遍历字典时会默认遍历所有键,将代码改为for key in student_score:
输出将不变 - ③按顺序遍历字典中的所有键,用函数
sorted()
,for name in sorted(student_score.keys()):
- ④遍历字典中的所有值,用
for value in student_score.values():
,该方法没有考虑值是否重复,为剔除重复项,可使用集合set
,它类似与列表,但每个元素都必须是独一无二的for name in set(student_score.values()):
6.4 嵌套
- 将一系列字典存储在列表中,或将列表作为值存储在字典中,也可以同种类型存储
aliens = []
#创建30个绿色外星人
for alien_number in range(30):
new_alien = {"color":"green","points":"5","speed":"slow"}
aliens,append(new_alien)
#修改前3个外星人
for alien in aliens[:3]:
if alien["color"] == "green":
alien["color"] = "yellow"
alien["points"] = 10
alien["speed"] = "medium"
elif alien["color"] == "yellow":
alien["color"] = "red"
alien["points"] = 15
alien["speed"] = "fast"
- 在字典中存储列表,这种情况下遍历该字典的for循环中,需要再使用一个for循环来遍历
for name,languages in favorite_languages.items():
print("
" + name.title() + "'s favorite languages are:")
for language in languages:
print(" " + language.title())
- 在字典中存储字典,尽量让每个键包含字典结构都相同,否则for循环内部的代码将更为复杂
第7章 用户输入和while循环
7.1 函数input()的工作原理
- 创建多行字符串的方式
prompt = "If you tell us who you are, we can personalize the message you see ."
prompt += "
what is your frist name?"
name = input(prompt)
print("
Hello," + name + "!")
- 使用函数
input()
时,将用户输入解读为字符串,可用函数int()
将字符串转化为数值 - 求模运算符
%
,指出余数是多少
7.2 while循环
- 学会使用标志控制程序运行:在要求很多条件都满足才继续运行的程序中,可定义一个变量,用于判断整个程序是否处于活动状态。这个变量被称为标志,充当程序的交通信号灯,可让程序在表示为
True
时继续运行,并在任何事件导致标志的值为False
时让程序停止运行。
active = True
while active:
message = input()
if message == "quit"
active = False
else:
print(message)
- 使用
break
退出循环 - 使用
continue
返回到循环开头,并根据条件测试结果决定是否继续执行循环,不像break
语句那样不再执行余下代码并退出整个循环 - 避免无限循环,确认程序至少有一个这样的地方能让循环条件为
False
或让break
语句得以执行
7.3 使用while循环来处理列表和字典
- for循环是一种遍历列表的有效方式,但在for循环中不应修改列表,否则将导致Python难以跟踪其中的元素,要在遍历列表的同时对其进行修改,可使用while循环
#先创建一个待验证用户列表和一个用于存储已验证用户的空列表
unconfirmed_user = ["a","b","c"]
confirm_users = []
#验证每个用户,直到没有未验证用户为止,将每个验证过的用户移到已验证用户列表中
while unconfirmed_user:
current_user = unconfirmed.pop()
print("Verifying user" + current_user.title())
confirmed_user.append(current.user)
#显示所有已验证的用户
print("
The following users have been confirmed:")
for confirmed_user in confirmed_users:
print(confirmed_user.title())
- 删除包含特定值的所有列表元素
while "cat" in pets:
pets.remove("cat")
- 使用用户输入来填充字典
responses = {}
#设置一个标志,指出调查问卷是否继续
polling_active = True
while polling_active:
#提示输入被调查者的名字和回答
name = input("
What is your name?")
response = input("Which moutain would you like to climb someday")
#将答卷存储在字典中
responses[name] = response
#看看是否还有人要参加调查
repeat = input("Would you like to let another person respond?(Y/N)")
if repeat == "N":
polling_active = False
#调查结束,显示调查结果
print(
---Poll Result---)
for name,response in responses.items():
print(name + "would like to climb " + response + ".")
第8章 函数
8.1 向函数传递信息
- 向函数传递信息
def greet_user(username):
print("Hello," + username.title() + "!")
greet_user("Jesse")
- 如上述变量
username
是一个形参,是函数完成其工作所需的一项信息;值Jesse
是一个实参,是调用函数时传递给函数的具体信息
8.2 传递实参
-
向函数传递实参的方式很多,可是使用位置参数,这要求实参的顺序与形参的顺序相同;也可以使用关键字实参,其中每个实参都有变量名和值组成;还可以使用列表和字典。
1、位置参数
调用函数时,将函数调用中的每个实参都关联到函数定义中的一个形参,这种关联方是被称为位置参数。优点是可以多次调用函数,但要注意实参的顺序与函数定义中形参的顺序一致。
2、关键字实参
是传递给函数的名称-值对,向函数传递时不会混淆,因此无需考虑函数调用中的实参顺序。
3、默认值
编写函数时,可以给每个形参指定默认值。使用默认值时,在形参列表中必须先列出没有默认值的形参,再列出有默认值的形参,这样才能正确地解读位置实参。
8.3 返回值
在函数中使用return
语句将值返回到调用函数的代码行,返回值让你能够将程序的大部分繁重工作移到函数中去完成,从而简化主程序。
- 调用返回值的函数时,需要提供一个变量,用于存储返回的值
- 使用默认值让实参变成可选的(末尾添加可选形参)
def get_formatted_name(first_name,last_name,middle_name=“ ”):
if middle_name: #python将非空字符解读为True
full_name = first_name + " " +middle_name + " " + last_name
else:
full_name = first_name + " " + last_name
return full_name.title()
musician = get_formatted_name("jimi","hendrix")
print(musician)
8.4 向函数传递列表
- 将列表传递给函数后,函数就可以对其进行修改,并且函数对这个列表所做的任何修改都是永久性的,这样能够高效地处理大量的数据。
- 使用函数与未使用函数的代码相比,组织更为有序,完成大部分工作的代码都移到了函数中,让主程序更容易理解。
- 禁止函数修改列表的方法,可向函数传递列表的副本而不是原件
funcition_name(list_name[:]) #用切片的方法创建列表的副本
,尽量用原始列表传递给函数,让函数使用现成列表可避免花时间和内存创建副本,提高效率,尤其是在处理大型列表时。
8.5 传递任意数量的实参
- 利用带星号的形参如
*toppings
,创建一个名为toppings
的空元祖,并将所有值都封装到这个元组中。def make_pizza(*toppings):
。 - 利用带双星号的形参如
**user_info
,创建一个名为user_info
的空字典,将任意数量的关键字参数封装到这个字典中。
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
- 当结合使用位置实数和任意数量实参时,python先匹位置实参,任意形参,任意关键字实参,默认形参。
8.6 将函数存储在模块中
- 函数的优点之一是,可以将代码块与主程序分离,给函数指定描述性名称,让主程序更易于理解。
- 导入模块的方法
(1)导入整个模块
编写一条import并在其中指定模块名import pizza
,模块的扩展名为.py
的文件,此时可以使用pizza
中定义的所有函数,调用函数时需要使用句点pizza.make_pizza()
。
(2)导入特定的函数from module_name import function_01,function_02
,from pizza import make_pizza
调用函数时无需使用句点。
(3)使用关键字as给函数指定别名from module_name import function_name as fn
(4)使用关键字as给模块指定别名import module_name as mn
(5)导入模块中的所有函数from module_name import *
- 调用函数时无需使用句点,但最好不要采用这种导入方法,可能遇到多个名称相同的函数或变量,进而覆盖函数。
8.7 函数编写指南
- 函数指定描述性名称,模块命名也同样。
- 每个函数都应包含简要地阐述其功能的注释,该注释应紧跟在函数定义后面,并采用文档字符串格式。
- 给形参指定默认值时,等号两边不要有空格,对于函数调用中的关键字实参,也应该遵循这种约定。
- 如果函数形参很多,可在函数定义中输入左括号后按回车,下行写,如:
def function_name(
parameter_0,parameter_2,parameter_3,
parameter_4,parameter_5,parameter_6)
function body.....
第9章 类
9.1 创建和使用类
- 定义一大类对象一般都有通用行为,基于类创建对象时,每个对象都自动具备这种通用行为,然后可根据需要赋予每个对象独特的个性
- 首字母大写的名称是指类
(1)方法__inif__()
- 类中的函数称为方法
- Python调用
__inif__()
方法来创建某个实例时,将自动传入实参self
,每个与类相关联的方法调用都自动传递实参self
,它是一个指向实例本身的引用,让实例能够访问类中的属性和方法。 - 以
self
为前缀的变量都可以供类中的所有方法使用,可以通过类的任何实例来访问这些变量。通过实例访问的变量称为属性。
9.1.2 根据类创建实例
(1)访问实例的属性
- 使用句点表示法:
my_dog.name
(2)调用方法
- 指定实例名称和要调用的方法:
my_dog.sit()
9.2 使用类和实例
(1)给属性指定默认值
- 类中的每个属性都必须有初始值,有些情况下,可以在方法
__init__()
内指定这种初始值;如果这样做了,就无需包含为它提供初始值的形参。
class Car():
def __init__(self,make,model,year):
"""初始化描述汽车的属性 """
self.make = make
self.model = model
self.year = year
self.odometer_reading = 0
my_new_car = Car('audi','a4','2016')
(2)修改属性的值
可以用三种不同的方法修改属性的值:直接通过实例进行修改;通过方法进行设置;通过方法进行递增(增加特定的值)
- 方法一:
my_new_car.odometer_reading = 23
- 方法二,编写对属性进行更新的方法,好处是无需直接访问属性,而可将值传递给一个方法,由它在内进行更新:
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!")
- 方法三:
def increment_odometer(self.miles):
"""将里程表读数增加指定的量"""
self.odometer_reading += miles
9.3 继承
一个类继承另外一个类时,它将自动获得另一个类的所有属性和方法;原有的类称为父类,而新类称为子类。子类继承了其父类的所有属性和方法,同时还可以定义自己的属性和方法。
(1)子类的方法__init__()
class ElectricCar(Car):
"""电动汽车的独特之处"""
def __init__(self,make,model,year):
"""初始化父类的属性"""
super().__init__(self,make,model,year)
- 定义子类时,必须在括号内指定父类的名称
-
super()
函数能将父类和子类关联起来,父类也称为超类,此处super()
等价于super(ElectricCar,self)
(2)给子类定义属性和方法
- 在方法
__init__()
中添加
(3)重写父类的方法
- 在子类中定义一个与要重写父类方法同名的方法,Python将不会考虑父类的方法,而只关注在子类定义的相应方法。
(4)将实例用作属性
- 当类中的属性和方法越来越多,可能需要将类的一部分作为一个独立的类提取出来,并将Battery这个独立类的实例作为另一个类ElectricCar的属性。
class Battery():
def __init__(self,battery_size=70):
self.battery_size = battery_size
class ElectricCar(Car):
def __init__(self,make,model,year):
"""初始化父类的属性,再初始化电动汽车特有的属性"""
super()__init__(make,model,year)
self.battery = Battery()
9.4 导入类
Python允许将类储存在模块中,然后在主程序中导入所需的模块。
- 导入单个类
from car import Car
使主程序文件变得整洁而易于阅读 - 从一个模块中导入多个类
from car import Car,ElectricCar
- 导入整个模块
import Car
- 导入模块中的所有类(不推荐)
from module_name import *
这种方式首先没有明确指出模使用了模块中的哪些类,其次容易重名引发报错 - 在一个模块中导入另一个模块
可能会发现一个模块中的类依赖于另外一个模块中的类,这种情况下,可在前一个模块中导入必要的类
9.5 类编码风格
- 类名采用驼峰命名法,即类名的每个单词的首字母都大写,而不使用下划线
- 实例名和模块名使用小写格式,并且单词之间加上下划线
- 对于每个类,都应紧跟在定义后包含一个文档字符串
- 利用空行来组织代码,在类中,使用一个空行来分隔方法;在模块中,使用两个空行来分隔类
第10章 文件和异常
10.1 从文件中读取数据
- 要使用文本文件中的信息,首先需要将信息读取到内存中。
with open("pi_digits.txt") as file_object: #函数open()返回一个表示文件的对象,有关键字with在,就不再需要访问文件后自动将其关闭
contents = file_object.read() #方法read()读取文件的全部内容
print(contents)
10.2文件路径
- 上述将文件名传递给函数
open()
时,Python将在当前执行的文件(即.py程序文件)所在的目录中查找文件。 - 在程序文件夹的其他子文件夹中,可以使用相对文件路径来打开文件夹中的文件,该位置是相对于当前运行的程序所在目录的。在Linux和OS X中,文件路径使用斜杠(/),在Windows系统中,文件路径使用反斜杠(),如:`with open('text_filesfilename.txt') as file_objetc:
- 也可以使用绝对文件路径,通常比相对路径更长,可以存储在一个变量中,便于使用。
- 由于反斜杠在Python中被视为转义标记,为在Windows中确保万无一失,应以原始字符串的方式指定路径,即在开头的单引号上加上
r
。
(1)逐行读取for line in file_object:
(2)创建一个包含文件各行内容的列表
- 使用关键字
with
时,open()
返回的文件对象只在with
代码块内使用,如果要在with
代码块外访问文件的内容,可在with
代码块内将文件的各行存储在一个列表,并在with
代码块外使用该列表。
with ope(filename) as file_object:
lines = file_object.readlines() #方法readlines()从文件中读取每一行,并将其存储在一个列表中
10.3 写入文件
- 在调用
open()
提供另一个实参with open(filename,"w") as file_object:
,w
表示以写入模式打开文件,如果指定文件已存在,将在返回文件对象前清空该文件;r
表示以读取模式打开文件,忽略实参时默认;a
表示以附加模式打开文件,如果指定的文件不存在,将创建一个空文件。 - Python只能将字符串写入文本文件
10.4 异常
- 异常使用try-except-else代码块处理。
- 好处:使异常避免崩溃,提供程序抵御错误的能力,避免用户看到
traceback
;避免恶意用户看到程序的文件名称和部分不能正确运行的代码。
print("Give me two numbers,and I'll divide them.")
print("Enter 'q' to quit.)
while True:
first_number = input("
First 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)
10.4.1 分析文本
- 方法
split()
以空格为分隔符将字符串拆分成多个部分,并将这些部分都存储到一个列表中。
>>> title = "Alice in Wonderland"
>>> title.split()
['Alice','in','Wonderland']
10.5 存储数据
- 使用模块
json
(JavaScript Object Notation)来存储数据,JSON格式存储的数据可以与使用其他编程语言的人分享。
10.5.1 使用json.dump()
和json.load()
- 函数
json.dump()
接受两个实参:要存储的数据以及可用存储数据的文件对象,通常使用文件扩展名.json
来指出文件存储的数据为JSON格式。
import json
numbers = [1,2,3,4,5] #如何用`json.dump()`来存储数字列表
filename = "numbers.json"
with open(filename,"w") as f_obj:
json_dump(numbers,f_obj)
new_numbers = json.load(f_obj) #使用`json.load()`将这个列表读取到内存中
10.5.2 代码重构
- 例子:保存和读取用户生成的数据
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)
print("We'll remember you when you come back ," + username + "!")
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
#函数要么返回None,要么返回预期的值,易于使用函数的返回值做简单测试
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()
第11章 测试代码
- 主要使用标准库中的unittest模块来测试代码(函数和类)
11.1 测试函数
- 单元测试:用于核实函数的某个方面是否符合要求
- 测试用例:是一组单元测试,用于一起核实函数在各种情况下的行为是否都符合要求
- 全覆盖式测试:包含一整套单元测试,涵盖了各种可能得函数使用方式
test_name_function.py
import unittest
from name_function import get_formatted_name #导入模块unittest以及要测试的函数,再创建一个继承unittest.TestCase的类
class NamesTestCase(unittest.TestCase): #创建一个继承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') #用断言方法来核实得到的结果是否与期望结果一致
unittest.main()
#让Python运行文件中的测试,所有test_打头的方法都将自动运行,因此被测试的方法名必须以test_打头
- 运行测试用例时,每完成一个单元测试,Python都打印一个字符:测试通过打印一个句点,测试引发错误打印一个
E
,测试导致断言失败打印一个F
- 测试未通过时,不要修改测试,而应修复导致测试不能通过的代码
11.2 测试类
- unittest.TestCase类中提供了各种断言方法,常用的6种:
方法 | 用途 |
---|---|
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中 |
- unittest.TestCase类包含方法
setUp()
,只需创建对象一次,就能在每个测试方法中使用它们,Python将先运行它,再运行各个以test_打头的方法
import unittest
from survey import AnonymousSurvey
class TestAnonymousSurvey(unittest.TestCase):
"""针对AnonymousSurvey类的测试"""
def setUp(self):
"""创建一个调查对象和一组答案,供测试方法使用"""
question = "What language did you first learn to speak?"
self.my_survey = AnonymousSurvey(question)
self.responses = ["English","Spanish","Mandarin"]
def test_store_single_response(self):
"""测试单个答案会被妥善地存储"""
self.my_survey.store_response(self.responses[0])
self.assertIn(self.response[0],self.my_survey.responses)
def test_store_three_response(self):
"""测试三个答案会被妥善地存储"""
for response in self.responses:
self.my_survey.store_response(response)
for resopnse in self.response:
self.assertIn(response,self.my_survey.responses)
unittest.main()