一、文件和异常
with open('10.txt') as file_object: # 函数open()接受一个参数,即要打开的文件的名称;with在不再需要访问文件后将其关闭
contents = file_object.read() # 方法read()读取这个文件的全部内容,在到达文件末尾时返回一个空字符串(打印出来是个空行)
print(contents)
with open(text_files\filename.txt) as file_object: # 相对文件路径(打开的文件位于py文件文件夹的子文件夹中)
file_path = 'C:\Users\May\Python\text_files\filename.txt'
with open(file_path) as file_object # 绝对文件路径(无需关心文件位于哪里)
filename = 'digits.txt'
with open(filename) as file_object:
for line in file_object: # file_object文件中每行末尾会有一个看不见的换行符
print(line)
filename = 'digits.txt'
with open(filename) as file_object:
lines = file_object.readlines() # 方法readlines()从文件中读取每一行
for line in lines:
print(line.rstrip())
-
- 使用文件中的内容(若将字符串转换为数值使用,函数int()转换为整数,函数float()转换为浮点数)
- 写入文件
- 写入空文件
- 写入模式'w'
- 读取模式'r'
- 附加模式'a'
- 读取和写入模式'r+'
filename = 'programming.txt'
with open(filename, 'w') as f_obj: # 第二个实参'w'告诉Python以写入模式打开文件,若文件不存在,则创建一个新文件;若存在,则覆盖原有内容
f_obj.write("I love programming")
>>> print(5/0)
Traceback (most recent call last):
File "division.py", line 1, in <module>
print(5/0)
ZeroDivisionError: division by zero
-
- 使用try-except代码块(返回一条友好信息而不是traceback)
try:
print(5/0) # 将导致错误的代码行放在一个try代码块中
except ZeroDivisionError: # 若try代码块没问题,将跳过except代码块
print("You can't divide by zero!")
-
- 使用异常避免崩溃
- else代码块(如果发生了指定的异常,该怎么做;若没发生,又该怎么做)
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
try:
answer = int(first_number) / int(second_number)
except ZeroDivisionError:
print("You can't divide by zero!")
else:
print(answer)
filename = 'alice.txt'
with open(filename) as f_obj:
contents = f_obj.read()
Traceback (most recent call last):
File "alice.py", line 3, in <module>
with open(filename) as f_obj:
FileNotFoundError: [Error 2] No such file or directory: 'alice.txt'
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)
>>> title = "Alice in Wonderland"
>>> title.split() # 方法split()根据一个字符串创建一个单词列表,以空格为分隔符将字符串分拆
['Alice', 'in', 'Wonderland']
-
- 使用多个文件
- try-except代码块提供了两个优点:避免让用户看到traceback;让程序能够继续分析能够找到的其他文件
- 失败时一声不吭
try:
--snip--
except FileNotFoundError:
pass # pass语句充当占位符
else:
--snip--
- 存储数据(使用json模块)
- JSON(JavaScript Object Notation)
- 使用json.dump(),接受两个实参:要存储的是数据以及可用于存储数据的文件对象
import json
numbers = [2, 3, 5, 7, 11, 13]
filename = 'numbers.json' # 文件扩展名.json表示文件存储的数据为JSON格式
with open(filename, 'w') as f_obj:
json.dump(numbers, f_obj) # 这个程序生成文件numbers.json,或覆盖文件原有内容,其数据的存储格式与Python一样
-
- 使用json.load():将文件数据读取到内存中
import json
filename = 'numbers.json'
with open(filename) 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'll remember you when you come bacck, " + username + "!")
else:
print("Welcome back, " + username + "!")
# 重构成一个函数
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'll remember you when you come back, " + username + "!")
else:
print("Welcome back, " + username + "!")
greet_user()
# 重构成两个函数
import json
def get_stored_username():
"""如果存储了用户名,就获取它"""
filename = 'username.json'
try:
with open(filename) as f_obj:
username = json.load(f_obj)
except FileNotFoundError:
return None
else:
return username
def greet_user():
"""问候用户,并指出其名字"""
username = get_stored_username()
if username:
print("Welcome back, " + username + "!")
else:
username = input("What is your name? ")
filename = 'username.json'
with open(filename, 'w') as f_obj:
json.dump(username, f_obj)
print("We'll remember you when you come back, " +username + "!")
greet_user()
# 重构成三个函数
import json
def get_stored_username():
--snip--
def get_new_username():
"""提示用户输入用户名"""
username = input("What is your name? ")
filename = 'useranme.json'
with open(fileaname, '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()
二、测试代码
- 测试函数:Python标准库中的模块unittest提供了代码测试工具
- 单元测试:用于核实函数的某个方面没有问题
- 测试用例:一组单元测试(全覆盖式测试用例)
# name_function.py测试代码
def get_formatted_name(first, last):
"""Generate a neatly formatted full name."""
full_name = first + ' ' + last
return full_name.title()
# test_name_function.py
import unittest
from name_function import get_formatted_name
class NamesTestCase(unittest.TestCase): # 该类用于包含一系列针对函数的单元测试,类名最好包含Test字样
"""测试name_function.py"""
def test_first_last_name(self): # 运行py文件时,以test_开头的方法都将自动运行
"""能够正确处理像May Zheng这样的姓名吗?"""
formatted_name = get_formatted_name('may', 'zheng')
self.assertEqual(formatted_name, 'May Zheng') # 一个断言方法
if __name__ == '__main__':
unittest.main()
# 输出
. # 句点表明有一个测试通过了
-----------------------------------------
Ran 1 test in 0.000s # 运行了一个测试,消耗的时间不到0.001s
OK # 测试用例中的所有单元测试都通过了
# 修改name_function.py如下
def get_formatted_name(first, middle, last):
"""生成整洁的名字"""
full_name = first + ' ' + middle + ' ' + last
return full_name.title()
# test_name_function.py
import unittest
from name_function import get_formatted_name
class NamesTestCase(unittest.TestCase): # 该类用于包含一系列针对函数的单元测试,类名最好包含Test字样
"""测试name_function.py"""
def test_first_last_name(self): # 运行py文件时,以test_开头的方法都将自动运行
"""能够正确处理像May Zheng这样的姓名吗?"""
formatted_name = get_formatted_name('may', 'zheng')
self.assertEqual(formatted_name, 'May Zheng') # 一个断言方法
if __name__ == '__main__':
unittest.main()
# 输出
E # 指出测试用例中有一个单元测试导致了错误
==================================================================================
ERROR: test_first_last_name (__main__,NamesTestCase)
----------------------------------------------------------------------------------
Traceback (most recent call last):
File "test_name_function.py", line 8, in test_first_last_name
formatted_name = get_formatted_name('may', 'zheng')
TypeError: get_formatted_name() missing 1 required positional argument: 'last'
----------------------------------------------------------------------------------
Ran 1 test in 0.000s
FAILED (errors=1)
-
- 测试未通过时:应修改导致测试不能通过的代码,而不是修改测试
# 修改name_function.py如下
def get_formatted_name(first, last, middle=''):
"""生成整洁的名字"""
if middle:
full_name = first + ' ' + middle + ' ' + last
else:
full_name = first + ' ' + last
return full_name.title()
# test_name_function.py
import unittest
from name_function import get_formatted_name
class NamesTestCase(unittest.TestCase): # 该类用于包含一系列针对函数的单元测试,类名最好包含Test字样
"""测试name_function.py"""
def test_first_last_name(self): # 运行py文件时,以test_开头的方法都将自动运行
"""能够正确处理像May Zheng这样的姓名吗?"""
formatted_name = get_formatted_name('may', 'zheng')
self.assertEqual(formatted_name, 'May Zheng') # 一个断言方法
def test_first_last_middle_name(self):
"""能够正确处理像May Yi Zheng这样的姓名吗?"""
formatted_name = get_formatted_name(
'may', 'zheng', 'yi')
self.assertEqual(formatted_name, 'May Yi Zheng')
if __name__ == '__main__':
unittest.main()
# 输出
..
-----------------------------------------------------------------------
Ran 2 tests in 0.000s
OK
- 测试类
- 各种断言方法(Python在unittest.TestCase类中提供了很多断言方法,断言方法检查你认为应该满足的条件是否满足)
unittest Module中的断言方法
| 方法 |
用途 |
| assertEqual(a,b) |
核实a == b |
| assertNotEqual(a,b) |
核实a != b |
| assertTrue(x) |
核实x为True |
| assertFalse(x) |
核实x为False |
| assertIn(item, list) |
核实item在list中 |
| assertNotIn(item, list) |
核实item不在list中 |
# 一个要测试的类,survey.py
class AnonymousSurvey():
"""收集匿名调查问卷的答案"""
def __init__(self, question):
"""存储一个问题,并为存储答案做准备"""
self.question = question
self.responses = []
def show_question(self):
"""显示调查问卷"""
print(self.question)
def store_response(self, new_response):
"""存储单份调查问卷"""
self.responses.append(new_response)
def show_results(self):
"""显示收集到的所有答卷"""
print("Survey results:")
for response in self.responses:
print('- ' + response)
# 测试AnonynousSurvey类,test_survey.py
import unittest
from survey import AnonymousSurvey
class TestAnonymousSurvey(unittest.TestCase):
"""针对AnonymousSurvey类的测试"""
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_responses(self):
"""测试三个答案会被妥善地存储"""
question = "What language did you first learn to speak?"
my_survey = AnonymousSurvey(question)
responses = ['English', 'Spanish', 'Mandarin']
for response in responses:
my_survey.store_response(response)
for response in responses:
self.assertIn(response, my_survey.responses)
if __name__ == '__main__':
unittest.main()
-
- 方法setUp():先运行setUp()方法,再运行以test_开头的方法(上述测试类额代码可以不用在每个方法中创建实例)
import unittest
from survey import AnonymousSurvey
class TestAnonymousSurvey(unittest.TestCase):
"""针对AnonymousSurvey类的测试"""
def setUp(self): # 在setUp()方法中创建一系列实例并设置它们的属性,再在测试方法中直接使用这些实例
"""
创建一个调查对象和一组答案,供使用的测试方法使用
"""
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.responses[0], self.my_survey.responses)
def test_store_three_responses(self):
"""测试三个答案会被妥善地存储"""
for response in self.responses:
self.my_survey.store_response(response)
for response in self.responses:
self.assertIn(response, self.my_survey.responses)
if __name__ == '__main__':
unittest.main()
-
- 每完成一个单元测试,Python都打印一个字符:
- 测试通过时:打印一个句点
- 测试引发错误时:打印一个E
- 测试导致断言失败时:打印一个F