笔记参考教程:(python蛇书)Python编程 从入门到时间(第2版)( [美]埃里克 · 马瑟斯 著 袁国忠 译 )
此文章为个人学习笔记,仅供学习交流,不作商业用途,如果侵权,请联系站长删除
Python学习笔记
1.变量和简单数据类型
1.1字符串
单引号和双引号都可以
“This is a string“
'This is also a string'
1.1.1“方法”
方法后面的 “ ( ) ” 是由于某些方法通常需要额外的信息来完成其工作
-
title()——每个单词首字母大写
names = "ada lovelace"
print(names.title())
------
#输出得
Ada Lovelace
-
upper()——全大写
-
lower()——全小写
names = "ada lovelace"
print(names.upper())
print(names.lower())
------
#输出得
ADA LOVELACE
ada lovelace
1.1.2变量
-
{}
first_name = "ada"
last_name = "lovelace"
full_name = f"{first_name} {last_name}"
print(full_name)
------
#输出得
ada lovelace
first_name = "ada"
last_name = "lovelace"
full_name = f"{first_name} {last_name}"
print(f"Hello,{full_name.title()}!")
------
#输出得
Hello,Ada LoveLace
1.1.3删除空白
-
rstrip()——删除字符后面的空
>>>favorite_language = 'python '
>>>favorite_language
'python '
>>>favorite_language.rstrip()
'python'
>>>favorite_language
'python '
-
lstrip()——删除字符前面的空
-
strip()——删除字符前后的空
1.2数
-
任意两个数相除,结果总是浮点数,即使这两个数都是整数且能整除
-
下划线——书写很大的数用下划线区分数字分组,使其清晰易读。当打印这种带下划线的数时,Python不会打印其中的下划线
>>>num = 12_000_000_000
>>>print(num)
12000000000
-
同时给多个变量赋值
x,y,z = 10,20,30
2.列表
2.1列表是什么
names = ['joe','zero','kent','peter']
print(names)
print(names[0])
message = 'names[0].title() is a good friend.'
print(message)
print(f"{names[0].title()} is a good friend.")
------
#输出得
['joe', 'zero', 'kent', 'peter']
joe
name[0].title() is a good friend.
Joe is a good friend.
如果直接让Python将列表打印出来,Python将打印列表的内部表示,包括方括号
2.2修改、添加和删除列表元素
2.2.1修改
names = ['joe','zro','kent','peter']
print(names)
names[0] = 'luffy'
print(names)
------
#输出得
['joe', 'zero', 'kent', 'peter']
['luffy', 'zero', 'kent', 'peter']
2.2.2添加
-
append()——在列表末尾添加元素
names = ['luffy','zoro','usopp','sanji']
names.append('nami')
print(names)
------
#输出得
['luffy', 'zoro', 'usopp', 'sanji', 'nami']
-
insert()——在列表中插入元素
names = ['luffy','zoro','usopp','sanji']
names.insert(1,'shanks')
print(names)
------
#输出得
['luffy', 'shanks', 'zoro', 'usopp', 'sanji']
2.2.3删除
-
del——永久删除
names = ['luffy','zoro','usopp','sanji']
print(names)
del names[0]
print(names)
------
#输出得
['luffy', 'zoro', 'usopp', 'sanji']
['zoro', 'usopp', 'sanji']
-
pop()——若括号中无值,则默认取出最后一个元素;否则,取出指定位置的元素
names = ['luffy','zoro','usopp','sanji']
print(names)
person1 = names.pop()
person2 = names.pop(0)
print(names)
print(person1)
print(person2)
------
#输出得
['luffy', 'zoro', 'usopp', 'sanji']
['zoro', 'usopp']
sanji
luffy
-
remove()——删除指定值的元素
names = ['luffy','zoro','usopp','sanji']
print(names)
names.remove('usopp')
print(names)
------
#输出得
['luffy', 'zoro', 'usopp', 'sanji']
['luffy', 'zoro', 'sanji']
2.3排序
-
print(-1)——打印倒数第一个元素
names = ['luffy','zoro','usopp','sanji']
print(names[-1])
print(names[-2])
------
#输出得
sanji
usopp
-
sort()——按字母顺序永久排列
-
sort(reverse = True)——按字母反序排列
names = ['luffy','zoro','usopp','sanji']
print(names)
names.sort()
print(names)
names.sort(reverse=True)
print(names)
------
#输出得
['luffy', 'zoro', 'usopp', 'sanji']
['luffy', 'sanji', 'usopp', 'zoro']
['zoro', 'usopp', 'sanji', 'luffy']
-
sorted()——临时排列
names = ['luffy','zoro','usopp','sanji']
print(sorted(names))
print(names)
------
#输出得
['luffy', 'sanji', 'usopp', 'zoro']
['luffy', 'zoro', 'usopp', 'sanji']
-
reverse()——反转列表元素顺序
names = ['luffy','zoro','usopp','sanji']
names.reverse()
print(names)
------
#输出得
['sanji', 'usopp', 'zoro', 'luffy']
-
len()——确定列表长度
names = ['luffy','zoro','usopp','sanji']
length = lennames)
print(length)
------
#输出得
4
2.4遍历
-
python中for循环语法:对于列表中的每个元素,都将执行循环指定的步骤,而不管列表包含多少个元素
for 变量 in 序列:
# 循环体语句
尤其注意,针对for循环,必须保证其循环后指定的步骤有相同的缩进
names = ['luffy','zoro','usopp']
for name in names:
print(f'{name.title()} is a character in OnePiece.')
print('And I like him/her.\n')
------
#输出得
Luffy is a character in OnePiece.
And I like him/her.
Zoro is a character in OnePiece.
And I like him/her.
Usopp is a character in OnePiece.
And I like him/her.
names = ['luffy','zoro','usopp']
for name in names:
print(f'{name.title()} is a character in OnePiece.')
print('And I like him/her.\n')
------
#输出得
Luffy is a character in OnePiece.
Zoro is a character in OnePiece.
Usopp is a character in OnePiece.
And I like him/her.
2.5创建列表
2.5.1使用函数range/list/append
-
rang()——生成一系列数。
e.g:range(1,5)只生成1至4,从1开始,到5结束,所以未生成5
for value in range(1,5)
print(value)
------
1
2
3
4
指定步长的range()
range(1,11,3):从1至11,步长为3
for numb in range(1,11,3):
print(numb)
------
1
4
7
10
-
list()——生成列表
numbs1 = range(1,5)
print(numbs1)
numbs2 = list(range(1,5))
print(numbs2)
------
range(1, 5)
[1, 2, 3, 4]
-
append()生成列表
numbs = []
for a in range(1,6):
numbs.append(a**2)
print(numbs)
------
[1, 4, 9, 16, 25]
其中,**表示乘方运算
2.5.2列表解析
numbs = [a**2 for a in range(1,11,3)]
print(numbs)
------
[1, 16, 49, 100]
2.6对数字列表进行统计运算
-
内置函数:
len()
:返回列表的长度(元素个数)。sum()
:返回列表中所有元素的和。min()
:返回列表中的最小值。max()
:返回列表中的最大值。sorted()
:返回一个排好序的列表副本。
numbers = [3, 5, 1, 2, 4]
length = len(numbers)
total = sum(numbers)
minimum = min(numbers)
maximum = max(numbers)
sorted_numbers = sorted(numbers)
print(length) # 输出:5
print(total) # 输出:15
print(minimum) # 输出:1
print(maximum) # 输出:5
print(sorted_numbers) # 输出:[1, 2, 3, 4, 5]
-
统计库 -
statistics
:
statistics
是Python的标准库之一,提供了执行统计计算的函数,如平均值、标准差、中位数等。需要导入statistics
模块才能使用。
import statistics
numbers = [3, 5, 1, 2, 4]
mean = statistics.mean(numbers) # 平均值
median = statistics.median(numbers) # 中位数
stdev = statistics.stdev(numbers) # 标准差
variance = statistics.variance(numbers)# 方差
print(mean) # 输出:3.0
print(median) # 输出:3
print(stdev) # 输出:1.5811388300841898
print(variance) # 输出:2.5
2.7列表切片
2.7.1切片
names = ['luffy','zoro','sanji','usopp','nami']
print(names[0:3]) #从0号元素开始,到3号元素终止
print(names[2:]) #从2号元素开始,到列表末尾所有元素
print(names[:3]) #从列表开始开始,终止到3号元素
print(names[-3:]) #从倒数第三个元素开始,到列表末尾所有元素
print(names[:]) #从列表开头到列表末尾的所有元素
------
['luffy', 'zoro', 'sanji']
['sanji', 'usopp', 'nami']
['luffy', 'zoro', 'sanji']
['sanji', 'usopp', 'nami']
['luffy', 'zoro', 'sanji', 'usopp', 'nami']
2.7.2遍历切片
names = ['luffy','zoro','sanji','usopp','nami']
for name in names[:3]:
print(name.title())
------
Luffy
Zoro
Sanji
2.7.3复制列表
-
先看 names_1 = names[:] 的情况
names = ['luffy','zoro','sanji','usopp','nami']
names_1 = names[:]
print(f'names_1 = {names_1}')
names.append('x')
names_1.append('y')
print(f'names_appended = {names}')
print(f'names_1_appended = {names_1}')
------
names_1 = ['luffy', 'zoro', 'sanji', 'usopp', 'nami']
names_appended = ['luffy', 'zoro', 'sanji', 'usopp', 'nami', 'x']
names_1_appended = ['luffy', 'zoro', 'sanji', 'usopp', 'nami', 'y']
-
再来观察直接赋值的情况 names_1 = names ,这种用法是错误的
names = ['luffy','zoro','sanji','usopp','nami']
names_2 = names
print(f'names_2 = {names_2}')
names.append('x')
names_2.append('y')
print(f'names_appended = {names}')
print(f'names_2_appended = {names_2}')
------
names_2 = ['luffy', 'zoro', 'sanji', 'usopp', 'nami']
names_appended = ['luffy', 'zoro', 'sanji', 'usopp', 'nami', 'x', 'y']
names_2_appended = ['luffy', 'zoro', 'sanji', 'usopp', 'nami', 'x', 'y']
可以看到,情况2的names_2实则就是names,而names_1才是names的副本。
即names_1是在names的基础上衍生出的一个新变量,而names_2只是与names相关联,可理解为names_2指向names。
2.8元组
列表是可变的,而元组是不可变的,但用来存储元组的变量是可以变的。
元组很像列表,但是元组使用圆括号而非中括号来标识。访问元组的过程同列表。
严格来说,元组是由逗号标识的,圆括号只是为了让元组看起来更加整洁和清晰。如果要定义一个只包含一个元素的元组,必须在这个元素的后面加上逗号。
numbs = (1123,118)
print(numbs[0])
print(numbs[1])
------
1123
118
若要尝试修改元组的值,则会产生报错
numbs = (1123,118)
numbs[0] = [666]
------
Traceback (most recent call last):
File "d:\Study\extracurricular\Python\temp.py", line 2, in
numbs[0] = [666]
~~~~~^^^
TypeError: 'tuple' object does not support item assignment
但修改元组变量指向的值是可以的
numbs = (1123,118)
print(numbs)
numbs = (1123,)
print(numbs)
------
(1123, 118)
(1123,)
3.if语句
-
通用语法
if 条件:
# 满足条件时执行的代码块
else:
# 不满足条件时执行的代码块
if 条件1:
# 满足条件1时执行的代码块
elif 条件2:
# 满足条件2时执行的代码块
elif 条件3:
# 满足条件3时执行的代码块
else:
# 所有条件都不满足时执行的代码块
-
and 如果你想要检查多个条件都为真,你可以使用 “and” 运算符。例如:
if 条件1 and 条件2:
# 当条件1 和 条件2 都为真时执行的代码
-
or 如果你想要检查多个条件中至少一个为真,你可以使用 “or” 运算符。例如:
if 条件1 or 条件2:
# 当条件1 或 条件2 其中一个为真时执行的代码
-
此外,你还可以结合使用括号来明确条件的组合关系。例如:
if (条件1 and 条件2) or 条件3:
# 当条件1 和 条件2 都为真,或者条件3为真时执行的代码
-
in 要检查特定值是否包含在列表中,你可以使用
in
运算符。示例如下:
my_list = [1, 2, 3, 4, 5]
if 3 in my_list:
# 当列表中包含值为 3 时执行的代码
-
not in 如果要检查特定值是否不包含在列表中,你可以使用
not in
运算符。示例如下:
my_list = [1, 2, 3, 4, 5]
if 6 not in my_list:
# 当列表中不包含值为 6 时执行的代码
-
布尔表达式
布尔表达式是一种逻辑表达式,用于在编程中表示条件判断的结果。布尔表达式的结果只能是两个值之一:True(真)或 False(假)。
布尔表达式通常使用比较运算符(如相等、大于、小于等)和逻辑运算符(如与、或、非等)进行构建,它们用于比较值、执行逻辑操作和连接多个条件。
Luffy = 'Pirate King'
print("Is Luffy the 'Pirate King'?I predict True!")
print("Luffy == 'Pirate King'") #print中为普通语句
print(Luffy == 'Pirate King') #print中为布尔表达式
------
Is Luffy the 'Pirate King'?I predict True!
Luffy == 'Pirate King'
True
4.字典
字典是一系列键值对,每个键都与一个值相关联。
4.1访问字典中的值
NikaMan = {'name': 'Luffy', 'gender': 'man','age':19 }
print(f'Nikaman is a {NikaMan["gender"]}.)
------
Nikaman is a man.
4.2添加键值对
NikaMan = {'name': 'Luffy', 'gender': 'man'}
print(NikaMan)
NikaMan['age'] = 19
print(NikaMan)
------
{'name': 'Luffy', 'gender': 'man'}
{'name': 'Luffy', 'gender': 'man', 'age': 19}
4.3删除键值对
-
del NikaMan[‘age’]
NikaMan = {'name': 'Luffy', 'gender': 'man','age': 19}
print(NikaMan)
del NikaMan['age']
print(NikaMan)
------
{'name': 'Luffy', 'gender': 'man', 'age': 19}
{'name': 'Luffy', 'gender': 'man'}
4.4字典另一种表达形式
favorite_language = {
'lixiang': 'python',
'z': 'c',
'kaifeng': 'cpp',
'lxq': 'java'
}
注意:每行后面的逗号 ‘,’ 不能掉
4.5使用get()来访问值
方法get()的第一个参数用来用于指定键,第二个参数为指定键不存在时要返回的值,是可选的。
favorite_language = {
'lixiang': 'python',
'z': 'c',
'kaifeng': 'cpp',
'lxq': 'java'
}
print(favorite_language.get('ncc','No such key'))
print(favorite_language.get('ncc'))
print(favorite_language.get('lxq','Can not find'))
------
No such key
None
java
4.6遍历字典
-
key
字典中的键 -
value
字典中的值 -
items()
是字典对象的方法 -
keys()
是访问字典键的方法 -
value()
是访问字典值的方法
Person = {'name': 'Z', 'gender': 'man', 'age': 20, 'PhoneNumbe':123456 }
for key,value in Person.items():
print(key,value)
------
name Z
gender man
age 20
PhoneNumbe 123456
其中,key和value不是一定的,只是一个命名,为了便于理解,可以用其他的命名方式,如下:
favorite_language = {
'Z': 'C',
'lx': 'Python',
'lxq': 'cpp',
'zkf': 'Java'
}
for name,language in favorite_language.items():
print(f"{name.title()}'s language is {language}")
------
Z's language is C
Lx's language is Python
Lxq's language is cpp
Zkf's language is Java
访问字典键和字典值的方法如下:
favorite_language = {
'Z': 'C',
'lx': 'Python',
'lxq': 'cpp',
'zkf': 'Java'
}
if 'ncc' not in favorite_language.keys():
print("NCC is not a key in favorite_language")
if 'Java' in favorite_language.values():
print("Somebody likes Java.")
------
NCC is not a key in favorite_language
Somebody likes Java.
favorite_language = {
'Z': 'C',
'lx': 'Python',
'lxq': 'cpp',
'zkf': 'Java'
}
keys = sorted(favorite_language.keys(),reverse = Ture)
for key in keys:
print(key.title())
------
Zkf
Lxq
Lx
Z
4.7嵌套
4.7.1在列表中存储字典
## Make an empty list for storing aliens.
aliens = []
## Make 30 green aliens.
for alien_number in range(30):
new_alien = {'color': 'green', 'points': 5, 'speed': 'slow'}
aliens.append(new_alien)
for alien in aliens[:3]:
if alien['color'] == 'green':
alien['color'] = 'yellow'
alien['speed'] = 'medium'
alien['points'] = 10
## Show the first 5 aliens.
for alien in aliens[:5]:
print(alien)
print("...")
4.7.2在字典中存储列表
# Store information about a pizza being ordered.
pizza = {
'crust': 'thick',
'toppings': ['mushrooms', 'extra cheese'],
}
## Summarize the order.
print(f"You ordered a {pizza['crust']}-crust pizza "
"with the following toppings:")
for topping in pizza['toppings']:
print("\t" + topping)
------
You ordered a thick-crust pizza with the following toppings:
mushrooms
extra cheese
4.7.3在字典中存储字典
users = {
'aeinstein': {
'first': 'albert',
'last': 'einstein',
'location': 'princeton',
},
'mcurie': {
'first': 'marie',
'last': 'curie',
'location': 'paris',
},
}
for username, user_info in users.items():
print(f"\nUsername: {username}")
full_name = f"{user_info['first']} {user_info['last']}"
location = user_info['location']
print(f"\tFull name: {full_name.title()}")
print(f"\tLocation: {location.title()}")
------
Username: aeinstein
Full name: Albert Einstein
Location: Princeton
Username: mcurie
Full name: Marie Curie
Location: Paris
5.用户输入与while循环
5.1 函数input工作原理
函数input()
让程序暂停运行,等待用户输入一些文本。获取用户输入后,Python将其赋给一个变量,以方便你使用。
messgae = input("Tell me something, and I will repeat it back to you: ")
print(message)
函数input()
接受一个参数,用于向用户显示提示或说明。
prompt = "\nTell me something, and I will repeat it back to you!"
prompt += "\nEnter 'quit' to end the program.\n>>>"
active = True
while active:
message = input(prompt)
if message == 'quit':
active = False
else:
print(message)
------
Tell me something, and I will repeat it back to you!
Enter 'quit' to end the program.
>>>Hello!
Hello!
Tell me something, and I will repeat it back to you!
Enter 'quit' to end the program.
>>>quit
5.1.1使用int()来获取数值输入
height = input("How tall are you, in inches? ")
height = int(height)
if height >= 48:
print("\nYou're tall enough to ride!")
else:
print("\nYou'll be able to ride when you're a little older.")
------
How tall are you, in inches? 60
You're tall enough to ride!
int(height)
将height中所得到的字符变量转换成数值变量,类似于C语言强制转换。
5.1.2求模运算符
%
将两个数相除并返回余数
>>> 4 % 3
1
>>> 5 % 3
2
>>> 6 % 3
0
5.2while循环
while循环中break
结束语句和continue
结束语句的区别
while
prompt = "\nPlease enter the name of a city you have visited!"
prompt += "\n(Enter 'quit' when you are finished.)\n"
while True:
city = input(prompt)
if city == 'quit':
break
else:
print(f"I'd love to go to {city.title()}!")
------
Please enter the name of a city you have visited!
(Enter 'quit' when you are finished.)
Wuhan
I'd love to go to Wuhan!
Please enter the name of a city you have visited!
(Enter 'quit' when you are finished.)
Shanghai
I'd love to go to Shanghai!
Please enter the name of a city you have visited!
(Enter 'quit' when you are finished.)
quit
continue
current_number = 0
while current_number < 10:
current_number += 1
if current_number % 2 == 0:
continue
print(current_number)
------
1
3
5
7
9
-
break
是终止整个while循环,continue
是终止本次while循环
6.函数
6.1传递实参
6.1.1位置实参
基于实参的顺序,将函数调用中的每个实参都关联到函数定义中的一个形参。
def describe_pet(animal_type, pet_name):
"""Display information about a pet."""
print(f"\nI have a {animal_type}.")
print(f"My {animal_type}'s name is {pet_name.title()}.")
describe_pet('cat', 'harry')
describe_pet('dog', 'willie')
使用位置实参来调用函数时,如果实参的顺序不正确,则会造成错误结果
6.1.2关键字实参
使用关键字实参时,实参的顺序无关紧要,Python能够自动识别哪个实参的具体值该赋给哪个形参
def describe_pet(animal_type, pet_name):
"""Display information about a pet."""
print(f"\nI have a {animal_type}.")
print(f"My {animal_type}'s name is {pet_name.title()}.")
describe_pet(animal_type='cat', pet_name='harry')
describe_pet(pet_name='willie', animal_type='dog')
6.1.3指定默认值的形参
def describe_pet(pet_name, animal_type='dog'):
"""Display information about a pet."""
print(f"\nI have a {animal_type}.")
print(f"My {animal_type}'s name is {pet_name.title()}.")
对上述带默认值的形参,以下几种函数调用都是等效的
#一只名为Willie的小狗
describe_pet('willie')
describe_pet(pet_name='willie')
#一只名为harry的小猫
describe_pet('harry', 'cat')
describe_pet(pet_name='harry', animal_type='cat')
describe_pet(animal_type='cat', pet_name='harry')
6.1.4可选实参
有的人无中间名,所有中间名这个参数是可选的,则将中间名放到函数形参的最后一个位置,以保证函数仅提供名和姓时该函数能够正确运行
def get_formatted_name(first_name, last_name, middle_name=''):
"""Return a full name, neatly formatted."""
if middle_name:
full_name = f"{first_name} {middle_name} {last_name}"
else:
full_name = f"{first_name} {last_name}"
return full_name.title()
musician = get_formatted_name('jimi', 'hendrix')
print(musician)
musician = get_formatted_name('john', 'hooker', 'lee')
print(musician)
------
Jimi Hendrix
John Lee Hooker
6.1.5传递任意数量的实参
1.*parameter
元组形参法
形参名*parameter
中的星号让Python创建一个名为parameter
的空元组,并将收到的所有值都封装到这个元组中。
def make_pizza(size, *toppings):
"""Summarize the pizza we are about to make."""
print(f"\nMaking a {size}-inch pizza with the following toppings:")
for topping in toppings:
print(f"- {topping}")
make_pizza(16,'pepperoni')
make_pizza(12,'mushrooms', 'green peppers', 'extea cheese')
------
Making a 16-inch pizza with the following toppings:
- pepperoni
Making a 12-inch pizza with the following toppings:
- mushrooms
- green peppers
- extea cheese
2.**parameter
字典形参法
def build_profile(first, last, **user_info):
"""Build a dictionary containing everything we know about a user."""
user_info['first_name'] = first
user_info['last_name'] = last
return user_info
user_profile = build_profile('albert', 'einstein',
location='princeton',
field='physics')
print(user_profile)
------
{'location': 'princeton', 'field': 'physics', 'first_name': 'albert', 'last_name': 'einstein'}
6.2函数返回值
返回字典的情况
def build_person(first_name, last_name, age=None):
"""Return a dictionary of information about a person."""
person = {'first': first_name, 'last': last_name}
if age:
person['age'] = age
return person
musician = build_person('jimi', 'hendrix', age=27)
print(musician)
6.3控制函数能否修改实参
Python中,将一个实参传进函数,函数是会修改实参的值的。
若不想改变实参的值,则传进函数中的应该是实参的副本。
例如对于列表,则用列表切片法[:]
建立副本,示例如下:
def change_list(list):
"""
改变列表的值
"""
while list:
del list[0]
subjects = ['math', 'physics', 'chemistry']
print(subjects)
change_list(subjects)
print(subjects)
------
['math', 'physics', 'chemistry']
[]
def change_list(list):
"""
改变列表的值
"""
while list:
del list[0]
subjects = ['math', 'physics', 'chemistry']
print(subjects)
change_list(subjects[:])
print(subjects)
------
['math', 'physics', 'chemistry']
['math', 'physics', 'chemistry']
6.4导入函数或模块
6.4.1导入整个模块
-
在
pizza.py
中编写函数make_pizza()
-
在
main.py
中使用import pizza
导入整个pizza.py
模块 -
使用
pizza.py
模块中的函数`make_pizza()’ -
使用格式:
pizza.make_pizza()
即**
module_name.function_name()
**注意:使用时文件名和函数名之间有句点!
6.4.2导入特定的函数
-
语法:
from module_name import function_name
-
使用逗号分隔函数名,可根据需要从模块中导入任意数量的函数:
from module_name import function0, function1, function2
-
使用这种语法时,为显式导入,调用函数时无须使用句点
6.4.3使用as
给函数指定别名
-
通用语法:
from module_name import function_name as fn
-
e.g.
from pizza import make_piza as mp mp(16,'pepperoni') mp(12,'mushrooms', 'green peppers', 'extea cheese')
6.4.4使用as
给模块指定别名
-
通用语法:
import module_name as mn
-
e.g.
import pizza as p p.make_pizza(16,'pepperoni') p.make_pizza(12,'mushrooms', 'green peppers', 'extea cheese')
6.4.5导入模块中的所有函数
-
优点:相较于导入整个模块,此方法导入整个模块中的所有函数可以**避免使用句点表示法**
-
缺点:使用自己编写的大型模块时,若采用这种表示方法,可能会由于模块中有函数的名称与当前项目中已有的函数名称相同,导致函数的覆盖和错误使用。
-
通用语法:
from module_name import *
7.类
PS:由于自己一个个字敲太花时间了,类的这部分笔记是直接copy后修改了一些,找的这一篇也都是照着蛇书一个个字敲的,所以也刚好“适配”和“兼容”,特别感谢作者!以下附链接:
面向对象编程是最有效的软件编写方法之一。在面向对象编程中,我们编写表示现实世界中事务和情景的类,并基于这些类创建。根据类来创建对象被称为实例化,这让我们能使用类的实例。
7.1 创建和使用类
7.1.1 创建Dog类
根据Dog类创建的每个实例都将存储名字和年龄。我们赋予了每条小狗蹲下(sit())和打滚(roll_over())的能力。
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!")
/print(f"{self.name} rolled over!")
根据约定,在Python中,首字母大写的名称指的是类,这个类定义中没有圆括号,因为我们要从空白创建这个类。
-
方法
_init_()
: -
类中的函数称为方法;
_ init_()
方法是一个特殊方法,每当我们根据Dog类创建实例时,python都会自动运行它。 -
在上面例子中我们将方法_init_()定义成包含三个形参:
self
,name
,age
。在这个方法的定义中,形参self
必不可少,而且要位于其他形参之前,这是因为python调用这个_init_()
方法创建实例时,将自动传入实参self。每个与类相关联的方法调用都自动传递实参self
,它是一个指向实例本身的引用,让实例能访问类中属性和方法。 -
我们创建Dog实例时,python将调用Dog类的方法
_init_()
。我们将通过实参向Dog()
传递名字和年龄;self
会自动传递,因此我们不需要传递它。 -
Dog类还定义了另外两个方法:
sit()
和roll_over()
。由于这些方法不需要额外的信息,如名字和年龄,因此它们只有一个形参self。
7.1.2 根据类创建实例
可将类视为有关如何创建实例的说明。Dog类是一系列说明,让Python知道如何创建表示特定小狗的实例。下面来创建一个表示特定小狗的实例:
class Dog:
def __init__(self,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!")
my_dog=Dog('willie',6)
print("My dog's name is"+my_dog.name.title()+".")
print("My dog is"+str(my_dog.age)+"year old.")
####
My dog's name isWillie.
My dog is 6 year old.
这里使用的是之前编写的Dog类,我们创建一条名字为 ‘wille’ ,年龄为6的小狗。遇到这行代码时,python使用实参 ‘wille’ 和 6调用Dog类中的方法 _ init_()
。方法_ _init_()
创建一个表示特定小狗的实例,并使用我们提供的值来设置属性name和age。方法_ init_()
并未显示的包含return语句,但python自动返回一个表示这条小狗的的实例。我们将这个实例存储在变量my_dog中。
调用方法
my_dog.sit()
my_dog.roll_over()
###
Willieis now sitting.
Willierolled over!
创建多个实例
my_dog = Dog('willie',6)
your_dog = Dog('lucy',3)
print("My dog's name is"+my_dog.name.title()+".")
print("My dog is "+str(my_dog.age)+" year old.")
my_dog.sit()
my_dog.roll_over()
print("\nYour dog's name is "+your_dog.name.title()+".")
print("Your dog is "+str(your_dog.age)+"years old.")
your_dog.sit()
your_dog.roll_over()
####
My dog's name isWillie.
My dog is 6 year old.
Willie is now sitting.
Willie rolled over!
Your dog's name is Lucy.
Your dog is 3 years old.
Lucyis now sitting.
Lucyrolled over!
在这里我们创建了两条小狗,分别命名为willie和lucy。每条小狗都是一个独立的实例,有自己的一组属性。
7.2使用类和实例
我们可以用类来模拟现实世界中的很多情景。类编写好后,我们的大部分时间都将花费在类创建的实例上。我们需要执行的一个重要任务是修改实例的属性。我们可以直接修改实例的属性,也可以编写方法以特定的方式进行修改。
7.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',2023)
print(my_new_car.get_descriptive_name())
###
2023 Audi A4
7.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):
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',2023)
print(my_new_car.get_descriptive_name())
my_new_car.read_odometer()
####
2023 Audi A4
This car has 0 miles on it.
上面程序中添加了一个名为odometer_reading
的属性,其初始值总是为0.我们还添加了一个名为read_odometer()
方法,用于读取汽车的里程表。
7.2.3 修改属性的值
可以以三种不同的方式修改属性的值:直接通过实例进行修改;通过方法进行设置;通过方法进行设置;通过方法进行递增(增加特定的值)。
-
直接修改属性的值
my_new_car.odometer_reading = 23
my_new_car.read_odometer()
####
This car has 23 miles on it.
-
通过方法修改属性的值
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!")
我们新增的
update_odometer()
会在修改属性前检查指定的读书是否合理。 -
通过方法对属性的值进行递增
class Car: --snip-- def update_odometer(self,mileage): --snip-- def increment_odometer(self,miles): """将里程表数增加一个指定的量""" self.odometer_reading += miles my_new_car=Car('subaru','outback',2013) print(my_new_car.get_descriptive_name()) my_new_car.update_odometer(23500) my_new_car.read_odometer() my_new_car.increment_odometer(100) my_new_car.read_odometer() #### 2013 Subaru Outback This car has 23500 miles on it. This car has 23600 miles on it.
新增的方法increment_odometer()接受一个单位为英里的数字,并将其加入到self.odometer_reading中。
7.3继承
编写类时,并非总是要从空白开始。如果我们要编写的类时另一个现成类的特殊版本,可以考虑使用继承。一个类继承另一个类时,它将自动获得另一个类的所有属性和方法;原有的类称为父类,而新的类称为子类。子类继承其父类的所有属性和方法,同时还可以定义自己属性和方法。
7.3.1子类的方法_init_()
下面,我们在前面创建的Car
类的基础上创建新类ElectricCar
,这样我们只需要为电动汽车特有的属性和行为编写代码。
创建子类时,父类必须包含在当前文件夹中,且位于子类前面。定义子类时,必须在圆括号内指定父亲的名称例如,下面定义子类时,ElectricCar
后又括号且括号中有内容Car
,即定义时,代码为class ElectricCar(Car)
。
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())
####
2016 Tesla Model S
super()
是一个特殊函数,帮助python将父类和子类关联起来。这行代码让python调用Car
父类的方法_init_()
,让ElectricCar实例包含这个方法中定义的所有属性。父类也称为超类,名称super
也由此而来。
7.3.2 给子类定义属性和方法
下面我们来添加一个电动车特有属性(电瓶),以及一个描述该属性的方法。我们将存储电瓶容量,并且编写一个打印电瓶描述的方法:
class Car:
--snip--
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.")
my_tesla = ElectricCar('tesla','model s',2016)
print(my_tesla.get_descriptive_name())
my_tesla.describe_battery()
####
2016 Tesla Model S
7.3.3 重写父类的方法
对于父类的方法,只要它有不符合子类模拟的实物的行为,都可以对其进行重写。为此,可以在子类中定义一个这样的方法,即它要与重写的父类方法同名。这样,python将只会关注我们在子类中定义的相应方法。
假设Car
类有一个名为fill_gas_tank()
的方法,它对全电动汽车来说毫无意义,因此你可能想重写它。下面演示了一种重写方式。
class ElectricCar(Car):
--snip--
def fill_gas_tank(self):
"""电动汽车没有油箱。"""
print("This car doenn't need a gas tank!")
3.1.3 重写父类的方法对于父类的方法,只要它有不符合子类模拟的实物的行为,都可以对其进行重写。为此,可以在子类中定义一个这样的方法,即它要与重写的父类方法同名。这样,python将只会关注我们在子类中定义的相应方法。
7.3.4 将实例用作属性
使用代码模拟实物时,我们可能会发现给类添加的细节越来越多:属性和方法清单以及文件都越来越长。在这种情况下,可能需要将类的一部分作为一个独立的类提取出来。我们可以将大类拆分成多个协同工作的小类。例如,不断给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.")
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()
####
2016 Tesla Model S
上面的代码看似做了很多额外的工作,但好处是现在我们多详细描述电瓶都可以,切不会导致ElectricCar
类混乱不堪。
7.4导入类
python允许我们将类存储在模块中,然后在主程序中导入所需的模块。
7.4.1 导入单个类
我们可以创建一个只包含Car
类的模块,我们可以将这个模块命名为car.py
。然后我们可以新创建其他文件,并在其中导入我们创建好的Car
模块。例如,我们创建新文件new_car
:
from car import Car
my_new_car=Car('auid','a4',2016)
print(my_new_car.get_descriptive_name())
my_new_car.odometer_reading =23
my_new_car.read_odometer()
第一句处的import
语句让python打开模块car
,并导入其中的Car
类,这样我们就可以使用Car
类了。
7.4.2 在一个模块中存储多个类
7.4.3 从一个模块中导入多个类
from car import Car,ElectriCar
7.4.4 导入整个模块
import car
7.4.5 导入模块中所有类
from module_name import *
不推荐这种方法,原因如下:
-
如果只看开头的
import
语句,就能清楚地知道程序使用了哪些类,将大有裨益。然而这种导入方式没有明确地指出使用了模块中的哪些类。 -
如果不小心导入了一个与程序文件中其他东西同名的类,将引发难以诊断的错误。
7.4.6使用别名
from electric_car import ElectricCar as EC
my_tesla = EC('tesla', 'roadster'. 2023)
7.5类编码风格
-
类名应该采用驼峰命名法,即将类名中的每个单词的首字母都大写,而不使用下划线
-
实例名和模块名都采用小写格式,并在单词之间加上下划线。
-
对于每个模块/类/方法,都应该在定义后面包含一个文档字符串
-
方法之间用一个空行来分隔,模块之间用两个空行来分隔
8.文件和异常
PS:同样,文件和异常的笔记也是在别的作者的基础上修改而得(原作者很多细节都直接忽略了,也由于蛇书的版本不同,补充修改了很多)
8.1文件部分参考出处:python - 文件操作(学习笔记)_stayfsh的博客-CSDN博客
8.2异常部分参考出处: Python学习笔记-异常及处理_Lance_Lewu的博客-CSDN博客
8.1 从文件中读取数据
文本文件可以存储的数据量非常多:天气数据,交通数据,社会经济数据,文学作品等等。每当需要分析和修改文件中的数据时,读取文件都是非常重要的,对数据分析更是如此。
8.1.1读取整个文件
pi_digits.txt
文件中存储的是小数点后30位的圆周率值,且在小数点后每10位处换行。
with open('pi_digits.txt') as file_object:
contents = file_object.read()
print(contents)
####
3.1415926535
8979323846
2643383279
-
关键字with
:在不需要访问文件后将其关闭。在此程序中,我们调用了open()
,但没有调用close()
,即打开了但没有关闭文件,但由于执行程序时close()
的位置往往不好确定,易产生bug导致文件未正常关闭,可能造成数据丢失或受损。且过早关闭往往会导致需要使用此文件时该文件已关闭。通过**关键字with
,Python
可以自己去确定关闭文件的时机(即with
**后缩进相同的部分)。 -
函数open()
:open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
常用参数说明(其他参数略):
-
file
:Python
在当前执行文件所在的目录查找指定文件。
-
mode :打开文件的模式,默认为
r
(只读模式)。常用的模式包括:
'r'
:只读模式。'w'
:写入模式,如果文件已存在则覆盖原有内容,若文件不存在则创建新文件。'a'
:追加模式/附加模式,将文本写入到文件末尾,若文件不存在则创建新文件。'x'
:独占创建模式,只在文件不存在时创建文件,若文件已存在则抛出异常。'b'
:二进制模式。't'
:文本模式(默认模式)。'+'
/r+
:更新模式,允许读写操作。
encoding
:用于指定文件的编码方式。例如,'utf-8'
。
-
方法read()
:读取文件。read()
到达文件末尾时返回一个空字符串,而将这个空字符串显示出来时就是一个空行。要删除多出来的空行,可在函数调用print()
中使用strip()
8.1.2文件路径
Python
默认在当前执行文件所在的目录查找指定文件,不会去搜寻子文件夹,更不能是上层文件夹。相对路径:
with open('text_files/filename.txt') as file_object:
绝对路径:
with open('C:/User/enmatthe/text_files/filename.txt') as file_object:
注意:
- 显示文件路径时,
Windows
系统使用反斜杠(\
)而不是斜杠(/
)- 如果在文件路径中直接使用反斜杠,将引发错误,因为反斜杠用于对字符串中的字符进行转义。e.g.路径
C:\Path\to\file.txt
中的\t
将被解读为制表符。如果一定要使用反斜杠,可对路径中的每个反斜杠都进行转义,如C:\\path\\to\\file.txt
8.1.3逐行读取文件
with open('pi_digits.txt') as file_object:
for line in file_object:
print(line)
####
3.1415926535
8979323846
2643383279
我们发现逐行读取这样操作由于每行末尾的换行符作用使得各行之间空白增多。所以我们可以使用rstrip()
方法来进行处理
print(line.rstrip())
8.1.4使用文件的内容
-
创建一个包含文件各行内容的列表
with open('pi_digits.txt') as file_object:
lines=file_object.readlines()
for line in lines:
print(line.rstrip())
####
3.1415926535
8979323846
2643383279
使用with
时,open()
返回的文件对象只能在with
代码块内使用,如果想在with
代码块外访问文件内容,可以在with
代码块内将文件的各行存储在一个列表中,并在with
代码块外使用列表就可以了。
-
使用文件
下面是一个简单的使用示例:
with open('pi_digits.txt') as file_object:
lines=file_object.readlines()
pi_string=''
for line in lines:
pi_string+=line.rstrip()
print(pi_string)
print(len(pi_string))
3.1415926535 8979323846 2643383279
36
如果使用strip()
方法来代替rstrip()
可以输出如下结果:
for line in lines:
pi_string+=line.strip()
####
3.141592653589793238462643383279
32
8.2异常
Python
使用称为异常的特殊对象来管理程序执行期间发生的错误。使用try-except
代码块处理。出现异常时,显示代码作者编写的友好的错误消息,而不是**traceback
,由于traceback
**报错时会显示部分程序代码,训练有素的攻击者往往会根据显示的部分代码而对程序发动定向攻击,造成程序的崩溃。
8.2.1try-except
代码块
try:
可能出现错误的语句段
except [指定的异常类型]: # 指定一种异常类型
出现该类异常以后的处理
except Exception as e: # 放在最后,兜底接收其他错误类型
print(e) # 输出错误信息
默认的错误处理
else:
try下代码块执行结束,没有遇到异常后,执行的代码块
finally:
无论有没有异常都会执行的代码块
Exception
是所有异常的父类,通常放在最后用来接收未知的错误类型.
**except
**后常见异常类型:
-
NameError
:名称错误,通常是由于访问了未定义的变量或函数导致的。 -
TypeError
:类型错误,通常是由于操作数的类型不匹配导致的。 -
ValueError
:值错误,通常是由于操作数的值不合法导致的。 -
KeyError
:键错误,通常是由于访问字典时使用了不存在的键导致的。 -
FileNotFoundError
:文件未找到错误,通常是由于尝试打开不存在的文件导致的。 -
ImportError
:导入错误,通常是由于无法导入模块或包导致的。 -
ZeroDivisionError
:除零错误,通常是由于进行了除零操作导致的。
8.2.2异常中return执行顺序
-
无finally
- try中有return: 立刻返回,结束程序段的执行
- else中有return: 立刻返回,结束程序段的执行
-
有finally
- try中有return而finally中无: 暂缓return,待finally执行完毕后返回
- else中有return而finally中无: 暂缓return,待finally执行完毕后返回
- finally中有return:无论try或else中是否有return,均以finally中返回的为准
异常传递
如果调用关系有多层,那么内层如果出错,错误就会被层层抛出,直到在某处被捕获或处理。如果直到最终调用处都未被捕获或处理,那么就会被抛出
自定义异常
当系统给定的异常不能满足需求时,可以使用自定义异常来进行补充
8.2.3自定义一个异常
class UserNameError(Exception):
def __init__(self,*args,**kwargs):
pass
#在方法中使用自定义异常
def setUserName():
username = input('请输入用户名:')
if len(username)<6 or username[0].isdigit():
raise UserNameError('用户名格式错误') # 用raise抛出异常
else:
print('输入成功')
try:
setUserName()
except Exception as e: # 接收异常
print(e)
8.3使用json.dump()
和json.load()
存储数据
很多程序要求用户输入某种信息,例如让用户存储游戏首选项或提供要可视化的数据。不管专注的是什么,程序都把用户提供的信息存储在列表和字典等数据结构中。要保存这些信息,一种简单的方法是使用json()
模块来存储数据。模块json
能让我们将简单的的python
数据结构转存储到文件中,并在文件运行时加载该文件中的数据。我们还可以使用json
在python
程序之间分享数据。
json
(JSON, JavaScript Obkect Notation
)格式最初是为JavaScript
开发的,但随后成立一种常见格式,被包括Python
在内的众多语言采用。
存储一组数字的例子:
import json
numbers = [2,3,5,7,11,13]
filename = 'numbers.json'
with open(filename,'w') as f:
json.dump(numbers,f)
json.dump()
是将数字列表存储到文件numbers.json
中,这个程序没有输出。json.dump()
接受两个实参:要存储的数据,以及可用于存储数据的文件对象。
下面再写一个程序,使用json.load()
将这个列表读取到内存中:
import json
filename = 'numbers.json'
with open(filename) as f:
numbers = json.load(f)
print(numbers)
####
[2, 3, 5, 7, 11, 13]
9.单元测试
单元测试是一种软件测试方法,用于测试程序的最小可测试单元(通常是函数或方法)是否按照预期进行工作。它的目的是确保单元在隔离的环境中能够正确、可靠地完成其指定的功能。
9.1unittest
单元测试格式
9.1.1单元测试框架:
-
unittest
:Python 标准库中的测试框架,使用类和方法来创建测试用例和测试套件。 -
pytest
:一个功能强大且易于使用的第三方测试框架,具有简洁的语法和丰富的插件生态系统。 -
doctest
:可以直接从函数的文档字符串中提取测试用例,并执行函数并验证输出结果是否符合预期。 -
其他第三方测试框架:如
nose
、nose2
、tox
等。
9.1.2格式:
在使用 unittest
进行单元测试时,有一些常用的格式和约定可以遵循,以提高测试代码的可读性和维护性。以下是一些常见的 unittest
测试单元的格式:
-
测试类的命名:测试类的命名通常以 “Test” 开头,后面跟着要测试的类的名称。例如,要测试名为
Calculator
的类,测试类的命名可以是TestCalculator
。 -
测试方法的命名:测试方法的命名通常以 “test_” 开头,后面跟着函数或方法的功能描述。例如,测试一个加法函数的功能,测试方法的命名可以是
test_addition()
。 -
导入和继承:在编写测试代码时,通常需要导入
unittest
模块,并创建一个继承自unittest.TestCase
的测试类。
import unittest
class TestCalculator(unittest.TestCase):
# 测试方法定义在这里
pass
-
断言语句:使用断言语句来验证测试的期望结果与实际结果是否一致。
unittest
提供了许多用于断言的方法,如assertEqual()
、assertTrue()
、assertFalse()
等。
def test_addition(self):
result = addition(2, 3)
self.assertEqual(result, 5)
-
使用
setUp()
和tearDown()
:在需要共享设置或资源的测试之间使用setUp()
和tearDown()
方法。setUp()
方法在每个测试方法之前执行一次,用于准备测试所需的环境。tearDown()
方法在每个测试方法之后执行一次,用于清理测试过程中创建的任何资源。
def setUp(self):
# 设置测试环境
def tearDown(self):
# 清理测试环境
-
运行测试:使用
unittest.main()
运行测试,它会执行测试类中的所有测试方法。
if __name__ == '__main__':
unittest.main()
-
使用
TestSuite
:如果需要自定义测试执行顺序,可以创建一个TestSuite
对象,并将测试方法添加到该对象中。
suite = unittest.TestSuite()
suite.addTest(TestCalculator("test_addition"))
suite.addTest(TestCalculator("test_subtraction"))
...
unittest.TextTestRunner().run(suite)
9.1.3示例:
import unittest # 必须步骤
def add(a, b):
return a + b
class TestAdd(unittest.TestCase): # 必须步骤
def test_1_plus_1(self):
result = add(1, 1)
self.assertEqual(result, 2) # 断言方法assert,核实得到的结果是否与期望的结果一致
def test_negative_numbers(self):
result = add(-5, -10)
self.assertEqual(result, -15)
def test_mixed_numbers(self):
result = add(3, -7)
self.assertEqual(result, -4)
if __name__ == '__main__': # 必须步骤
unittest.main()
在上述示例中,我们使用 unittest
框架编写了一个简单的测试用例。测试用例是通过创建一个继承自 unittest.TestCase
的类,并在其中定义以 test_
开头的测试方法来实现的。每个测试方法都使用断言语句来验证函数的返回值是否与预期结果一致。最后,在 __main__
中调用 unittest.main()
来执行测试。
当执行这段代码时,测试框架将会执行所有的测试方法并输出测试结果。如果所有的断言都为真,则测试通过;如果有任何一个断言失败,则测试失败,并输出详细的错误信息。
9.2setUp()
方法
在单元测试中,setUp()
方法是 unittest.TestCase
类中的一个特殊方法,在每个测试方法执行之前被调用。setUp()
方法可以用来设置测试环境,进行一些初始化操作,以确保每个测试方法都在相同的环境中运行。
setUp()
方法的主要作用是为每个测试方法创建一个干净的测试环境,并在该环境中进行实际的测试操作。在该方法中可以进行一些常见的设置工作,例如创建测试数据、连接数据库、打开文件或初始化对象等。
下面是一个示例,展示了如何在单元测试中使用 setUp()
方法:
import unittest
class ExampleTestCase(unittest.TestCase):
def setUp(self):
# 设置测试环境
self.data = [1, 2, 3, 4, 5]
def test_sum(self):
# 在测试方法中使用设置的数据进行测试
result = sum(self.data)
self.assertEqual(result, 15)
def test_length(self):
# 在测试方法中使用设置的数据进行测试
length = len(self.data)
self.assertEqual(length, 5)
if __name__ == '__main__':
unittest.main()
在上面的示例中,我们创建了一个名为 ExampleTestCase
的测试类。在 setUp()
方法中,我们初始化了一个名为 data
的列表,该列表将在每个测试方法中被使用。
然后,在两个测试方法 test_sum()
和 test_length()
中,我们使用了 data
列表进行实际的测试。我们分别计算了列表元素的和并进行断言,以及计算列表的长度并进行断言。
每次执行测试时,setUp()
方法都会在每个测试方法之前执行一次,确保每个测试方法都在同样的环境下进行操作,以提供可靠的测试结果。
需要注意的是,setUp()
方法只会在每个测试方法开始之前执行一次,即使测试类中有多个测试方法,也只会执行一次。如果你希望在每个测试方法之后执行一些清理操作,可以使用 tearDown()
方法来完成。