一、文件和异常
- 从文件中读取数据
- 读取整个文件
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")
-
- 附加到文件('a',将内容添加到文件末尾)
- 异常(使用try-except代码块处理)
- 处理ZeroDivisionError异常
>>> print(5/0) Traceback (most recent call last): File "division.py", line 1, inprint(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)
-
- 处理FileNotFoundError异常
filename = 'alice.txt' with open(filename) as f_obj: contents = f_obj.read() Traceback (most recent call last): File "alice.py", line 3, inwith 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)
-
- 分析文本(项目Gutenberg提供了一系列不受版权限制的文学作品)
>>> 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类中提供了很多断言方法,断言方法检查你认为应该满足的条件是否满足)
方法 | 用途 |
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
- 每完成一个单元测试,Python都打印一个字符: