什么专业可以做网站编辑,碳晶板装修多少钱一平方,免费注册店铺位置,小程序怎么开发《Python编程#xff1a;从入门到实践》学习笔记 1.文件和异常
1.1 从文件中读取数据
1.1.1 读取整个文件 要读取文件#xff0c;需要一个包含几行文本的文件。下面首先来创建一个文件#xff0c;它包含精确到小数 点后30位的圆周率值#xff0c;且在小数点后每10位处都换… 《Python编程从入门到实践》学习笔记 1.文件和异常
1.1 从文件中读取数据
1.1.1 读取整个文件 要读取文件需要一个包含几行文本的文件。下面首先来创建一个文件它包含精确到小数 点后30位的圆周率值且在小数点后每10位处都换行 pi_digits.txt 3.1415926535 8979323846 2643383279 下面的程序打开并读取这个文件再将其内容显示到屏幕上
with open(pi_digits.txt) as file_object:contents file_object.read()print(contents)open函数表示打开文件关键字with在不再需要访问文件后将其关闭使用方法read()读取这个文件的全部内容并将其作为一个长长的字符串存储在变量content中。
print(contents.rstrip()) Python方法rstrip()删除剥除字符串末尾的空白。现在输出与原始文件的内容完全相同
运行结果
3.1415926535 8979323846 2643383279
1.1.2 文件路径 当你将类似pi_digits.txt这样的简单文件名传递给函数open()时Python将在当前执行的文件即.py程序文件所在的目录中查找文件。根据你组织文件的方式有时可能要打开不在程序文件所属目录中的文件。 在Linux和OS X中你可以这样编写代码 with open(text_files/filename.txt) as file_object: 这行代码让Python到文件夹python_work下的文件夹text_files中去查找指定的.txt文件。在Windows系统中在文件路径中使用反斜杠\而不是斜杠/ with open(text_files\filename.txt) as file_object: 注意 Windows系统有时能够正确地解读文件路径中的斜杠。如果你使用的是Windows系统且结果不符合预期请确保在文件路径中使用的是反斜杠。 1.1.3 逐行读取 读取文件时常常需要检查其中的每一行你可能要在文件中查找特定的信息或者要以某种方式修改文件中的文本。 要以每次一行的方式检查文件可对文件对象使用for循环
filename text_file\pi_digits.txt
with open(filename) as file_object:for line in file_object:print(line.rstrip())运行结果
3.1415926535 8979323846 2643383279
1.1.4 创建一个包含文件各行内容的列表 使用关键字with时open()返回的文件对象只在with代码块内可用。如果要在with代码块外访问文件的内容可在with代码块内将文件的各行存储在一个列表中并在with代码块外使用该列表你可以立即处理文件的各个部分也可推迟到程序后面再处理。 下面的示例在with代码块中将文件pi_digits.txt的各行存储在一个列表中再在with代码块外打印它们
filename text_file\pi_digits.txt
with open(filename) as file_object:lines file_object.readlines()for line in lines:print(line.rstrip()) 方法readlines()从文件中读取每一行并将其存储在一个列表中接下来该列表被存储到变量lines中在with代码块外我们依然可以使用这个变量。最后我们使用一个简单的for循环来打印lines中的各行。由于列表lines的每个元素都对应于文件中的一行因此输出与文件内容完全一致。
运行结果
3.1415926535 8979323846 2643383279
1.1.5 使用文件的内容 将文件读取到内存中后就可以以任何方式使用这些数据了。
filename text_file\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))
运行结果
3.141592653589793238462643383279 32 注意 读取文本文件时Python将其中的所有文本都解读为字符串。如果你读取的是数字并要将其作为数值使用就必须使用函数int()将其转换为整数或使用函数float()将其转换为浮点数。 1.2 写入文件 保存数据的最简单的方式之一是将其写入到文件中。通过将输出写入文件即便关闭包含程序输出的终端窗口这些输出也依然存在你可以在程序结束运行后查看这些输出可与别人分享输出文件还可编写程序来将这些输出读取到内存中并进行处理。
1.2.1 写入空文件 要将文本写入文件你在调用open()时需要提供另一个实参告诉Python你要写入打开的文件。为明白其中的工作原理我们来将一条简单的消息存储到文件中而不是将其打印到屏幕上
filename programming.txt
with open(filename, w) as file_object:file_object.write(I love programming.) 在这个示例中调用open()时提供了两个实参。第一个实参也是要打开的文件的名称第二个实参w告诉Python我们要以写入模式打开这个文件。打开文件时可指定读取模式r、写入模式w、附加模式a或让你能够读取和写入文件的模式r。如果你省略了模式实参Python将以默认的只读模式打开文件。 如果你要写入的文件不存在函数open()将自动创建它。然而以写入w模式打开文 件时千万要小心因为如果指定的文件已经存在Python将在返回文件对象前清空该文件。 我们使用文件对象的方法write()将一个字符串写入文件。这个程序没有终端输出但如果你打开文件programming.txt将看到其中包含如下一行内容
programming.txt I love programming. 注意 Python只能将字符串写入文本文件。要将数值数据存储到文本文件中必须先使用函数str()将其转换为字符串格式。 1.2.2 写入多行 函数write()不会在你写入的文本末尾添加换行符因此如果你写入多行时需要加指定换行符
filename programming.txt
with open(filename, w) as file_object:file_object.write(I love programming.\n)file_object.write(I love creating new games.\n)
现在输出出现在不同行中
programming.txt I love programming. I love creating new games. 像显示到终端的输出一样还可以使用空格、制表符和空行来设置这些输出的格式。
1.2.3 附加到文件 如果你要给文件添加内容而不是覆盖原有的内容可以附加模式打开文件。你以附加模式打开文件时Python不会在返回文件对象前清空文件而你写入到文件的行都将添加到文件末尾。如果指定的文件不存在Python将为你创建一个空文件。 下面来修改write_message.py在既有文件programming.txt中再添加一些你酷爱编程的原因
filename programming.txt
with open(filename, a) as file_object:file_object.write(I also love finding meaning in large datasets.\n)file_object.write(I love creating apps that can run in a browser.\n) open(filename, a) 打开文件时指定了实参a以便将内容附加到文件末尾而不是覆盖文件原来的内容。我们又写入了两行它们被添加到文件programming.txt末尾
programming.txt I love programming. I love creating new games. I also love finding meaning in large datasets. I love creating apps that can run in a browser. 1.3 异常
1.3.1 使用try-except 代码块
当你认为可能发生了错误时可编写一个try-except代码块来处理可能引发的异常。
try:print(5 / 0)
except ZeroDivisionError:print(You cant divide by zero!)
运行结果
You cant divide by zero!
1.4 存储数据 很多程序都要求用户输入某种信息如让用户存储游戏首选项或提供要可视化的数据。不管专注的是什么程序都把用户提供的信息存储在列表和字典等数据结构中。用户关闭程序时你几乎总是要保存他们提供的信息一种简单的方式是使用模块json来存储数据。 模块json让你能够将简单的Python数据结构转储到文件中并在程序再次运行时加载该文件中的数据。你还可以使用json在Python程序之间分享数据。更重要的是JSON数据格式并非Python专用的这让你能够将以JSON格式存储的数据与使用其他编程语言的人分享。这是一种轻便式很有用也易于学习。 注意 JSONJavaScript Object Notation格式最初是为JavaScript开发的但随后成了一种常见 格式被包括Python在内的众多语言采用。 1.4.1 使用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) 这个程序没有输出但我们可以打开文件numbers.json看看其内容。数据的存储格式与 Python中一样 [2, 3, 5, 7, 11, 13] 下面再编写一个程序使用json.load()将这个列表读取到内存中
import json
filename numbers.json
with open(filename) as f_obj:numbers json.load(f_obj)
print(numbers)
输出结果 [2, 3, 5, 7, 11, 13] 1.4.2 保存和读取用户生成的数据 对于用户生成的数据使用json保存它们大有裨益因为如果不以某种方式进行存储等程序停止运行时用户的信息将丢失。
import json
filenameusername.json
try:with open(filename) as read:username json.load(read)
except FileNotFoundError:username input(What is your name? )with open(filename, w) as write:json.dump(username, write)print(Well remember you when you come back, username !)else:print(Welcome back, username !) 无论执行的是except代码块还是else代码块都将显示用户名和合适的问候语。如果这个程序是首次运行输出将如下 What is your name? kangkang Well remember you when you come back, kangkang! 否则输出将如下 Welcome back, kangkang! 这是程序之前至少运行了一次时的输出。
1.4.3 重构 你经常会遇到这样的情况代码能够正确地运行但可做进一步的改进——将代码划分为一系列完成具体工作的函数。这样的过程被称为重构。重构让代码更清晰、更易于理解、更容易扩展。
import json
def get_stored_username():如果存储了用户名就获取它filename username.jsontry:with open(filename) as f_obj:username json.load(f_obj)except FileNotFoundError:return Noneelse:return usernamedef get_new_username():提示用户输入用户名username input(What is your name? )filename username.jsonwith open(filename, w) as f_obj:json.dump(username, f_obj)return usernamedef greet_user():问候用户并指出其名字username get_stored_username()if username:print(Welcome back, username !)else:username get_new_username()print(Well remember you when you come back, username !)greet_user()
第一次运行结果 What is your name? kangkang Well remember you when you come back, kangkang! 否则输出将如下 Welcome back, kangkang! 这是程序之前至少运行了一次时的输出。
2.测试代码
2.1 测试函数
2.1.1 可通过的测试 创建测试用例的语法需要一段时间才能习惯但测试用例创建后再添加针对函数的单元测试就很简单了。要为函数编写测试用例可先导入模块unittest以及要测试的函数再创建一个继承unittest.TestCase的类并编写一系列方法对函数行为的不同方面进行测试。下面是一个只包含一个方法的测试用例它检查函数get_formatted_name()在给定名和姓时能否正确地工作
name_function.py
def get_formatted_name(first, last):Generate a neatly formatted full name.full_name first lastreturn full_name.title()test_name_ function.py
import unittest
from name_function import get_formatted_name
class NamesTestCase(unittest.TestCase):测试name_function.pydef test_first_last_name(self):能够正确地处理像Janis Joplin这样的姓名吗formatted_name get_formatted_name(janis, joplin)self.assertEqual(formatted_name, janis Joplin)
unittest.main()结果 Ran 1 test in 0.000s
OK 第1行的句点表明有一个测试通过了。接下来的一行指出Python运行了一个测试消耗的时 间不到0.000秒。最后的OK表明该测试用例中的所有单元测试都通过了。 上述输出表明给定包含名和姓的姓名时函数get_formatted_name()总是能正确地处理。修改get_formatted_name()后可再次运行这个测试用例。如果它通过了我们就知道在给定Janis Joplin这样的姓名时这个函数依然能够正确地处理。
2.1.2添加新测试 确定get_formatted_name()又能正确地处理简单的姓名后我们再编写一个测试用于测试包含中间名的姓名。为此我们在NamesTestCase类中再添加一个方法
name_function.py
def get_formatted_name(first, last, middle):生成整洁的姓名if middle:full_name first middle lastelse:full_name first lastreturn full_name.title()test_name_ function.py
import unittest
from name_function import get_formatted_name
class NamesTestCase(unittest.TestCase):测试name_function.pydef test_first_last_name(self):能够正确地处理像Janis Joplin这样的姓名吗formatted_name get_formatted_name(janis, joplin)self.assertEqual(formatted_name, Janis Joplin)def test_first_last_middle_name(self):能够正确地处理像Wolfgang Amadeus Mozart这样的姓名吗formatted_name get_formatted_name(wolfgang, mozart, amadeus)self.assertEqual(formatted_name, Wolfgang Amadeus Mozart)unittest.main()
结果 Ran 2 tests in 0.000s
OK 2.2 测试类
2.2.1 各种断言方法 Python在unittest.TestCase类中提供了很多断言方法。前面说过断言方法检查你认为应该满足的条件是否确实满足。如果该条件确实满足你对程序行为的假设就得到了确认你就可以确信其中没有错误。如果你认为应该满足的条件实际上并不满足Python将引发异常。 下表描述了6个常用的断言方法。使用这些方法可核实返回的值等于或不等于预期的值、返回的值为True或False、返回的值在列表中或不在列表中。你只能在继承unittest.TestCase的类中使用这些方法。
unittest Module中的断言方法 方法用途assertEqual(a, b)核实a bassertNotEqual(a, b)核实a ! bassertTrue(x)核实x为TrueassertFalse(x)核实x为FalseassertIn(item, list)核实item在list中assertNotIn(item, list)核实item不在list中
2.2.2 一个要测试的类 类的测试与函数的测试相似——你所做的大部分工作都是测试类中方法的行为但存在一些不同之处下面来编写一个类进行测试。来看一个帮助管理匿名调查的类
survey.py
class AnonymousSurvey():收集匿名调查问卷的答案def __init__(self, question):存储一个问题并为存储答案做准备self.question questionself.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) 这个类首先存储了一个你指定的调查问题并创建了一个空列表用于存储答案。这个类包含打印调查问题的方法、在答案列表中添加新答案的方法以及将存储在列表中的答案都打印出来的方法。要创建这个类的实例只需提供一个问题即可。有了表示调查的实例后就可使用show_question()来显示其中的问题可使用store_response()来存储答案并使用show_results()来显示调查结果。
为证明AnonymousSurvey类能够正确地工作我们来编写一个使用它的程序
from survey import AnonymousSurvey
#定义一个问题并创建一个表示调查的AnonymousSurvey对象
question What language did you first learn to speak?
my_survey AnonymousSurvey(question)
#显示问题并存储答案
my_survey.show_question()
print(Enter q at any time to quit.\n)
while True:response input(Language: )if response q:breakmy_survey.store_response(response)
# 显示调查结果
print(\nThank you to everyone who participated in the survey!)
my_survey.show_results() 这个程序定义了一个问题What language did you first learn to speak? 并使用这个问题创建了一个AnonymousSurvey对象。接下来这个程序调用show_question()来显示问题并提示用户输入答案。收到每个答案的同时将其存储起来。用户输入所有答案输入q要求退出后调用show_results()来打印调查结果 What language did you first learn to speak? Enter q at any time to quit.
Language: english Language: ai Language: chaince Language: q
Thank you to everyone who participated in the survey! Survey results: - english - ai - chaince 2.2.3 测试AnonymousSurvey 类 下面来编写一个测试对AnonymousSurvey类的行为的一个方面进行验证如果用户面对调查问题时只提供了一个答案这个答案也能被妥善地存储。为此我们将在这个答案被存储后使用方法assertIn()来核实它包含在答案列表中
test_survey.py
import unittest
from survey import AnonymousSurvey
class TestAnonmyousSurvey(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)
unittest.main()
当我们运行test_survey.py时测试通过了 ---------------------------------------------------------------------- Ran 1 test in 0.000s
OK 这很好但只能收集一个答案的调查用途不大。下面来核实用户提供三个答案时它们也将被妥善地存储。为此我们在TestAnonymousSurvey中再添加一个方法
import unittest
from survey import AnonymousSurvey
class TestAnonmyousSurvey(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)unittest.main() 我们再次运行test_survey.py时两个测试针对单个答案的测试和针对三个答案的测试都通过了 ---------------------------------------------------------------------- Ran 2 tests in 0.000s
OK 前述做法的效果很好但这些测试有些重复的地方。下面使用unittest的另一项功能来提高它们的效率。
2.2.4 方法setUp() 在前面的test_survey.py中我们在每个测试方法中都创建了一个AnonymousSurvey实例在每个方法中都创建了答案。unittest.TestCase类包含方法setUp()让我们只需创建这些对象一次并在每个测试方法中使用它们。如果你在TestCase类中包含了方法setUp()Python将先运行它再运行各个以test_打头的方法。这样在你编写的每个测试方法中都可使用在方法setUp()中创建的对象了。 下面使用setUp()来创建一个调查对象和一组答案供方法test_store_single_response()和test_store_three_responses()使用
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.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)unittest.main()
运行结果 .. ---------------------------------------------------------------------- Ran 2 tests in 0.000s
OK 注意 运行测试用例时每完成一个单元测试Python都打印一个字符测试通过时打印一个句点测试引发错误时打印一个E测试导致断言失败时打印一个F。这就是你运行测试用例时在输出的第一行中看到的句点和字符数量各不相同的原因。如果测试用例包含很多单元测试需要运行很长时间就可通过观察这些结果来获悉有多少个测试通过了。