《Python编程:从入门到实践》基础知识总结

文章目录

  • 字符串
  • 列表
    • 添加和删除元素
    • 组织列表
    • 创建数字列表
    • 使用列表的一部分
    • 元组
  • 字典
    • 遍历字典
    • 嵌套
      • 字典列表
      • 在字典中存储列表
      • 在字典中存储字典
  • 输入与循环
    • 使用标志
  • 函数
    • 传递实参
      • 传递列表
        • 禁止函数修改列表
      • 传递任意数量的实参
    • 返回值
    • 将函数存储在模块中
    • 创建和使用类
      • 创建Dog类
        • 方法__init__()
      • 根据类创建实例
    • 使用类和实例
      • 给属性指定默认值
      • 修改属性的值
    • 继承
      • 子类的方法__init__()
      • 重写父类的方法
      • 将实例用作属性
    • 导入类
    • Python标准库
    • 类编码风格
  • 文件和异常
    • 从文件中读取数据
      • 读取整个文件
      • 文件路径
      • 逐行读取
      • 创建一个包含文件各行内容的列表
      • 使用文件的内容
      • 圆周率值中包含你的生日吗
    • 写入文件
      • 写入空文件
      • 附加到文件
    • 异常
      • 处理ZeroDivisionError异常
      • 使用异常避免崩溃
      • else代码块
      • 处理FileNotFoundError异常
    • 存储数据
      • 使用json.dump()和json.load()
      • 保存和读取用户生成的数据
    • 重构
  • 测试代码
    • 测试函数
      • 可通过的测试
      • 不可通过的测试
      • 添加新测试
    • 测试类
      • 各种断言方法
      • 一个要测试的类
      • 测试AnonymousSurvey类
      • 方法setUp()
  • 总结


字符串

name="ada lovelace"
name.title()#首字母大写
name.upper()#转换成大写
name.lower()#转换成小写
\t制表符
\n换行符
name=' python '
name.rstrip()#去掉字符串末尾空白
name.lstrip()#去掉字符串开头空白
name.strip()#去掉字符串两端空白
#以后方法返回一个新的字符串,不修改原字符串的值
str()#类型转换函数,避免类型错误
name.replaced('ada', 'Ada')#替换字符串中内容
name.split()#分隔单词,返回一个列表

列表

添加和删除元素

#添加元素
append()#在列表末尾添加元素
ls=[]#创建空列表
insert(i,num)#在索引i处插入元素num
#删除元素
del ls[0]#删除列表任意位置的元素,前提是知道索引
ls.pop()#删除列表末尾元素并返回
ls.pop(i)#删除索引为i处的元素并返回
ls.remove(num)#根据值删除元素,只删除第一个指定的值,删除多个要用循环判断

组织列表

#sort()对列表进行永久性排序
ls.sort()#顺序排列
ls.sort(reverse=True)#逆序排列

#sorted()对列表进行临时排序
sorted(ls)
sorted(ls,reverse=True)
ls.reverse()#永久将列表反转
len(ls)#返回列表长度

创建数字列表

#使用函数range()
range(1,5)#生成序列1,2,3,4
range(2,11,2)#指定步长为2
list(range(1,5))#将range的结果转换为列表

min(ls)
max(ls)
sum(ls)

#列表解析
#将for循环和创建新元素的代码合并为一行,并自动附加新元素
ls=[value**2 for value in range(1,11)]

使用列表的一部分

处理列表的部分元素,python称之为切片

ls[0:3]#返回下标为0、1、2的元素组成的列表
ls[:3]#未指定起始索引,python将自动从列表开头开始
ls[0:]#未指定终止索引,python将返回从0到列表末尾的所有元素
ls[-3:]#返回倒数后三个元素

#复制列表
#使用切片,切片会生成一个新的副本
ls_copy=ls[:]
#直接复制,其实指向同一个列表
ls_copy=ls

元组

列表是可以修改的,有时需要创建一系列不可修改的元素,元组可以满足这种需求。python将不能修改的值称为不可变的,而不可变的列表被称为元组
虽然不能修改元组的元素,但是可以给存储元组的变量赋值。


字典

字典可以用来高效模拟现实世界中的情形。字典可以用来存储一个对象的多种信息,也可以用来存储众多对象的同一种信息。
在python中,字典是一系列键-值对
字典是一种动态结构,可随时在其中添加键-值对。

dict={'color':'green','point':5}
dict['color']#访问字典中的值
dict[x_position] = 0#添加键值对
dict={}#创建空字典
#删除键值对,使用del
del dict['color']

#将较大的字典存储在多行中,注意缩进
dict={
	'jen':'python',
	'sarch':'c',
	'phil':'C++',
	}

#将较长的print语句分成多行,在合适的地方拆分,每行末尾加上拼接运算符(+)
print("Sarch's favorite language is "+
	dict['sarah'].title()+
	".")

遍历字典

items()、keys()、values()

dict.items()#返回一个键值对列表
for k,v in dict.items()#注意键值对的返回顺序与存储顺序不同
#python不关心键值对的存储顺序,只关心其关联关系
dict.keys()#返回键列表
sorted(dict.keys())#对键列表排序
dict.values()#返回值列表
set()#集合,不包含重复值
set(dict.values())#剔除值列表中的重复值

嵌套

字典列表

经常需要在列表中包含大量的字典,而其中每个字典都包含特定对象的众多信息。

在字典中存储列表

每当需要在字典中将一个键关联到多个值时,都可以在字典中嵌套一个列表。

在字典中存储字典

比如,一个网站把用户信息存储在一个字典中,字典的键是用户名,字典的值是用户的个人信息,也是一个字典。


输入与循环

input()#python将输入解读为字符串
int()#将变量的类型转换成数字

使用标志

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


函数

"""
文档字符串
python使用它们生成程序中函数的文档
"""

传递实参

位置实参:要求实参的顺序与形参的顺序相同。
关键字实参:形参名=实参这种形式传递参数。
默认值:有默认值的形参要放在最后。可以让实参变为可选的。

传递列表

将列表传递给函数后,函数就可以对其进行修改,在函数中对这个列表所做的任何修改都是永久性的,这可以让你高效地处理大量的数据。

禁止函数修改列表

可以向函数传递列表的副本而不是原件,这样函数所做的修改都只影响副本,而不影响原件。
function_name(list_name[:])
虽然向函数传递列表的副本可以保留原始列表的内容,但是会花费时间和内存创建副本,从而影响效率,尤其是在处理大型列表时。因此没有充足理由还是不要传递副本。

传递任意数量的实参

def make_pizza(*toppings):
形参名*toppings中的星号让python创建一个名为toppings的空元组,并将收到的所有值都封装在这个元组中。
python将实参封装到一个元组中,即便函数只收到一个值也如此。

def build_profile(first,last,**user_info):
**user_info接受任意数量的关键字实参,类型是字典

返回值

使用return语句
函数可以返回任何类型的值,包括列表字典等较复杂的数据结构。

将函数存储在模块中

将函数存储在被称为模块的独立文件中,再将模块导入到主程序中。
模块是扩展名为**.py**的文件,包含要导入到程序中的代码。
所导入模块要与程序在同一目录下

"""导入整个模块"""
import pizza
module_name.function_name()#使用模块中的某个函数
"""导入特定的函数"""
from module_name import function_1,function_2
function_1()#无需使用句点,在import语句中显式地导入了函数
"""使用as给函数指定别名"""
from pizza import make_pizza as mp
"""使用as给模块指定别名"""
import pizza as p
"""导入模块中所有函数"""
from pizza import *

在并非自己编写的大型模块中,最好不要导入模块中所有函数。
如果模块中有函数的名称与你的项目中使用的名称相同,可能会导致意想不到的结果:python可能遇到多个名称相同的函数或变量,进而覆盖函数,而不是分别导入所有的函数。
最佳的做法:要么只导入你需要的函数,要么导入整个模块并使用句点表示法


面向对象编程是最有效的软件编写方法之一。它可以用来模拟现实情景,其逼真程度超乎你想象。

创建和使用类

创建Dog类

根据约定,在python中,首字母大写的名称指的是类。
类中的函数称为方法,与函数的差别是调用方法的方式

class Dog():
	"""一次模拟小狗的简单尝试"""

	def __init__(self,name,age):
		"""初始化属性name和age"""
		self.name = name
		self.age = age
	
	def sit(self):
		"""模拟小狗被命令时蹲下"""
		print(self.name.title() + " is now sitting.")

	def roll_over(self):
		"""模拟小狗被命令时打滚"""
		print(self.name.title() + " rolled over!")
#方法sit()和roll_over()所做的有限,它们只是打印一条消息,指出小狗正蹲下或打滚。
#但可以扩展这些方法以模拟实际情况,可以创建小狗蹲下和打滚动画效果的代码等。
方法__init__()

__init__是一个特殊的方法,每当你根据Dog类创建新实例时,python都会自动运行它。
在这个方法的名称中,开头和结尾各有两个下划线,这是一种约定,旨在避免python默认方法与普通方法发生名称冲突。
我们将方法__init__()定义成了包含三个形参:self、name和age。在这个方法的定义中,形参self必不可少,还必须位于其他形参的前面。

为何必须在方法定义中包含形参self呢?

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

根据类创建实例

my_dog =  Dog('willie', 6)
#调用属性
my_dog.name
#调用方法
my_dog.sit()

使用类和实例

给属性指定默认值

类中的每个属性都必须有初始值,哪怕这个值是0或空字符串。在这种情况下,如设置默认值时,在方法__init__()内指定这种初始值是可行的。

	def __init__(self,name,age):
		"""初始化属性name和age"""
		self.name = name
		self.age = age
		self.value = 0#指定默认值为0

修改属性的值

  • 直接修改属性的值
  • 通过方法修改属性的值
  • 通过方法对属性的值进行递增

继承

  • 编写类时,并非总是要从空白开始。如果你要编写的类是另一个类现成类的特殊版本,可使用继承
  • 一个类继承另一个类时,它将自动获得另一个类的所有属性和方法;原有的类称为父类,而新类称为子类。父类也称为超类(superclass)
  • super()是一个特殊函数,帮助Python将父类与子类关联起来。
  • 子类继承了其父类所有的属性和方法,同时还可以定义自己的属性和方法。定义子类时,必须在括号中指定父类的名称。
  • 创建子类时,父类必须包含在当前文件中,且位于子类前面。

子类的方法__init__()

class ElectricCar(Car):
	"""
	电动汽车的独特之处
	初始化父类的属性,再初始化电动汽车特有的属性
	"""
	
	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.")

重写父类的方法

对子类调用重写方法,将忽略父类中的方法。使用继承,可以让子类保留从父类那里继承而来的精华,并剔除不需要的糟粕。

将实例用作属性

使用代码模拟实物时,给类添加的细节越来越多:属性和方法清单以及文件都越来越长。
在这种情况下,可能需要将类的一部分作为一个独立的类提取出来。可以将大型类拆分成多个协同工作的小类。
为了使代码简洁易读、便于维护

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

class ElectricCar(Car):
	......
	def __init__(self, make, model, year):
		"""初始化父类属性"""
		super().__init__(make, model, year)
		self.battery = Battery()

导入类

"""导入单个类"""
from car import Car
#import语句让Python打开模块car,并导入其中Car类
"""在一个模块中存储多个类"""
"""从一个模块中导入多个类"""
from car import Car, ElectricCar
"""导入整个模块"""
import car
my_beetle = car.Car('volkswagen', 'beetle', 2016)
"""导入模块中的所有类"""
from module_name import *

"""在一个模块中导入另一个模块"""
"""一个模块中的类依赖于另一个模块中的类"""
#electric_car.py
from car import Car

Python标准库

"""模块collections中的一个类————OrderedDict"""
"""OrderedDict类记录了键-值对的添加顺序,兼具列表和字典的主要优点"""
from collections inport OrderedDict
favorite_languages = OrderedDict()

"""模块random包含以各种方式生成随机数的函数"""
"""randint返回一个位于指定范围内的整数"""
from random import randint
x = randint(1, 6)

类编码风格

  • 类名应采用驼峰命名法,即将类名中的每个单词的首字母都大写,而不使用下划线。实例名和模块名都采用小写格式,并在单词之间加上下划线。
  • 对于每个类,都应紧跟在类定义后面包含一个文档字符串,简要描述类的功能,并遵循编写函数的文档字符串时采用的格式约定。每个模块也都应包含一个文档字符串,对其中的类可用于做什么进行描述。
  • 类中,可使用一个空行来分隔方法;在模块中。可使用两个空行来分隔类。
  • 编写导入标准模板库的import语句和编写导入你自己编写的模块的import语句之间应该间隔一个空行。

文件和异常

从文件中读取数据

读取整个文件

"""pi_digits.txt"""
3.1415926535
  8979323846
  2643383279
"""file_reader.py"""
with open('pi_digits.txt') as file_object:
	contents = file_object.read()
	print(contents)
	#print(contents.rstrip())
"""
使用文件之前要打开文件,函数open()接受一个参数:要打开的文件的名称
python在当前执行的文件所在目录中查找指定的文件
函数open()返回一个表示文件的对象
关键字with在不再需要访问文件时将其关闭,比close()更好用更安全
read()读取文件内容,到达文件末尾时返回一个空字符串,也会显示
如果想要删除可以在print语句中使用rstrip()
"""

文件路径

python只会在当前文件夹下查找,而不会在其子文件夹中查找。可以采用相对路径绝对路径
由于在Python中反斜杠()被视为转义标记,为确保在Windows系统中万无一失,应以原始字符串的方式指定路径,即在开头的单引号前加上r
file_path = r'C:\Users\...\text_files\filename.txt'

"""使用相对文件路径"""
#在Linux和OS X中
with open('text_files/pi_digits.txt') as file_object:
#在Windows中(反斜杠)
with open('text_files\pi_digits.txt') as file_object:
"""使用绝对路径"""
#在Linux和OS X中
file_path = '/home/ehmatthes/other_files/text_files/filename.txt'
with open(file_path) as file_object:
#在Windows中
file_path = 'C:\Users\ehmatthes\other_files\text_files\filename.txt'
with open(file_path) as file_object:

逐行读取

filename = 'pi_digits.txt'
with open(filename) as file_object:
	for line in file_object:
		print(line)
		print(line.rstrip())
#文件每行的末尾都有一个看不见的换行符,print()语句也会加上一个换行符

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

filename = 'pi_digits.txt'

with open(filename) as file_object:
	lines = file_object.readlines()
	#从文件中读取每一行,存储在一个列表中

for line in lines:
	print(line.rstrip())

使用文件的内容

filename = 'pi_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)
print(len(pi_string))

圆周率值中包含你的生日吗

birthday = input("Enter your birthday, in the form mmddyy:")
if birthday in pi_string:
	xxxx
else:
	xxxx

写入文件

写入空文件

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

文件打开模式 ‘r’ ‘w’ ‘a’ ‘r+’ 忽略模式实参
读取模式 写入模式 附加模式 读取和写入 默认只读
filename = 'programming.txt'

with open(filename, 'w') as file_object:
	file_object.write("I love gramming.")
	#写入多行
	#file_object.write("I love creating new games.")
	#write()不会在写入的文件末尾添加换行符,需要自己加上'\n'

附加到文件

附加模式下,写入到文件中的内容都添加到文件末尾。如果指定的文件不存在,Python将为你创建一个空文件。

异常

Python使用称为异常的特殊对象来管理程序执行期间发生的错误。
异常是使用try-except代码块处理的。try-except代码块让Python执行指定的操作,同时告诉Python发生异常时怎么办。
使用try-except代码块时,即便出现异常,程序也将继续执行:显示你编写的友好的错误消息,而不是令用户迷惑的traceback。

处理ZeroDivisionError异常

try:
	print(5/0)
except ZeroDivisionError:
	print("You can't divide by zero!")
"""如果try-except代码块后面还有其他代码,程序将接着运行"""

使用异常避免崩溃

程序崩溃可不好。但让用户看到traceback也不是好主意。
不懂技术的用户会被它们搞糊涂,而且如果用户怀有恶意,他会通过traceback获悉你不希望他知道的信息
例如,他将知道你的程序文件的名称,还将看到部分不能正确运行的代码。有时候,训练有素的攻击者可根据这些信息判断出可对你的代码发起什么样的攻击。

else代码块

try:
	answer = int(a) / int(b)
except ZeroDivisionError:
	print("You can't divide by zero!")
else:
	print(answer)

处理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."
	print(msg)	
	#pass 
"""什么都不做的话,except中可以使用pass"""

存储数据

使用模块json(JavaScript Object Notation)来存储数据。
模块json让你能够将简单的Python数据结构转储到文件中,并在程序再次运行时加载该文件中的数据。

使用json.dump()和json.load()

函数json.dump()接受两个实参:要存储的数据以及可用于存储数据的文件对象

import json

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

filename = 'numbers.json'
with open(filename, 'w') as f_obj:
	json.dump(numbers, f_obj)
"""
查看内容,数据的存储格式与Python一样
[2, 3, 5, 7, 11, 13]
"""

使用json.load()将这个列表读取到内存中

import json

filename = 'numbers.json'
with open(filename, 'w') as f_obj:
	numbers = json.load(f_obj)

print(numbers)
"""这是一种在程序中共享数据的简单方式"""

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

#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 will remember you when you come back, " + username + "!")
else:
	print("Welcome back, " + username + "!")

重构

你经常会遇到这样的情况:代码能够正确的运行,但可做进一步的改进——把代码划分成一系列完成具体工作的函数。这样的过程被称为重构
重构可以让代码更清晰、更易于理解、更容易扩展。

要重构remember_me.py,可以将大部分逻辑放在一个或多个函数中。remember_me.py的重点是问候用户,因此我们将其所有代码放在一个名为greet_user()的函数中:

import json
def greet_user():
	"""问候用户,并指出其名字"""
	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 will remember you when you come back, " + username + "!")
	else:
		print("Welcome back, " + 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 will remember you when you come back, " + 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 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 will remember you when you come back, " + username + "!")
	
greet_user()

测试代码

测试函数

  • Python标准库中的模块unittest提供了代码测试工具。
  • 单元测试用于核实函数的某个方面没有问题;测试用例是一组单元测试,这些单元测试一起核实函数在各种情形下的行为都符合要求。良好的测试样例考虑到了函数可能收到的各种输入,包含针对所有这些情形的测试。
  • 全覆盖式测试样例包含一整套单元测试,涵盖了各种可能的函数使用方式。对于大型项目,要实现全覆盖可能很难。通常,最初只要针对代码的重要行为编写测试即可,等项目被广泛使用时再考虑全覆盖。

可通过的测试

创建测试样例的语法需要一段时间才能习惯,但测试样例创建后,再添加针对函数的单元测试就简单了。
要为函数编写测试样例,可先导入模块unittest以及要测试的函数,再创建一个继承unittest.TestCase的类,并编写一系列方法对函数行为的不同方面进行测试。

test_name_function.py

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.assertEqule(formatted_name, 'Janis Joplin')

unittest.main()
  1. 我们运行test_name_function.py时,所有以test_打头的方法都将自动运行。
  2. unittest类最常用的功能之一:一个断言方法。
    断言方法用来核实得到的结果是否与期望的结果一致。
  3. 代码行unittest.main()让Python运行这个文件中的测试

不可通过的测试

测试未通过时怎么办呢?
如果你检查的条件没错,测试通过了,意味着函数的行为是对的,而测试未通过,意味着你编写的新代码有错,因此测试未通过时不要修改测试,而应修复导致测试不能通过的代码:检查刚对函数所做的修改,找出导致函数行为不符合预期的修改。

添加新测试

def test_first_last_middle_name(self):

测试类

各种断言方法

python在unittest.TestCase类中提供了很多断言方法。断言方法检查你认为应该满足的条件是否确实满足。
以下列出常用的6个断言方法,你只能在继承unittest.TestCase的类中使用这些方法。

方法 用途
assertEqual(a,b) 核实a==b
assertNotFound(a,b) 核实a!=b
assertTrue(x) 核实x为True
assertFalse(x) 核实x为False
assertIn(item, list) 核实item在list中
assertNotIn(item, list) 核实item不在list中

一个要测试的类

类的测试和函数的测试相似——你所做的大部分工作都是测试类中方法的行为,但存在一些不同之处,下面来编写一个类进行测试。
来看一个帮助管理匿名调查的类:
survey.py

class AnnoymousSurvey():
	"""收集匿名调查问卷的答案"""

	def __init__(self, question):
		"""存储一个问题,并为存储答案做准备"""
		self.question = question
		self.responses = []
	
	def show_questions(self):
		"""显示调查问卷"""
		print(self.question)
	
	def store_quesion(self, new_response):
		"""存储单份调查答卷"""
		self.response.append(new_response)
	
	def show_results(self):
		"""显示收集到的所有答卷"""
		print("Survey results:")
		for response in self.responses:
			print('- ' + response)

测试AnonymousSurvey类

test_survey.py

import unittest
from survey import AnonymousSurvey

class TestAnnoymousSurvey(unittest.TestCase):
	"""针对AnnoymousSurvey类的测试"""

	def test_store_single_response(self):
		"""测试单个答案会被妥善地存储"""
		question = "What language did you first learn to speak?"
		my_survey = AnnoymousSurvey(question)
		my_survey.store_response('English')

		self.assertIn('English', my_survey.responses)

	def test_store_three_responses(self):
		"""测试三个答案会被妥善地存储"""
		question = "What language did you first learn to speak?"
		my_survey = AnnoymousSurvey(question)
		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()

unittest.TestCase类包含方法setUp(),让我们只需创建这些对象一次,并在每个测试方法中使用它们。如果你在TestCase类中包含了方法setUp(),Python将先运行它,再运行各个以test_打头的方法。这样你编写的每个测试方法都可以使用在方法setUp()中创建的对象了。

import unittest
from survey import AnonymousSurvey

class TestAnnoymousSurvey(unittest.TestCase):
	"""针对AnnoymousSurvey类的测试"""

	def setUp(self):
		"""
		创建一个调查对象和一组答案,供使用的测试方法使用
		"""
		question = "What language did you first learn to speak?"
		self.my_survey = AnnoymousSurvey(question)
		self.responses = ['English', 'Spanish', 'Mandarin']
		
	def test_store_single_response(self):
		"""测试单个答案会被妥善地存储"""
		self.my_survey.store_response(self.response[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()

方法setUp()做了两件事情:

  • 创建一个调查对象
  • 创建一个答案列表

存储这两个东西的变量名包含前缀self(即存储在属性中),因此可以在类的任何地方使用。

运行测试用例时,每完成一个单元测试,,Python都会打印一个字符:测试通过时打印一个句点;测试引发错误时打印一个E;测试导致断言失败时打印一个F。这就是你运行测试用例时,在输出的第一行中看到的句点和字符数量各不相同的原因。


总结

一天时间总结了《Python编程 从入门到实践》的第一部分(1—11章)。
后续将发布第二部分:项目的有关文章以及Python的进阶教程
对于本书省略或是未讲清楚的内容,请查看原书。
如果觉得有帮助,请给博主点个赞~

你可能感兴趣的:(python,单元测试)