Python学习笔记(三)

Python学习笔记(三),第1张

文件和异常

使用文本文件的信息,需要将信息读取到内存中。



读取整个文件
创建文件pi_digits.txt

file_reader.py
with open('pi_digits.txt') as file_object:
	contents=files_object.read()
	print(contents)

关键字with在不需要访问文件后将其关闭,read()到达文件末尾会返回一个空字符串,空字符串输出就是一个空行。


删除末尾的空行,可以在print语句中使用rstrip()

print(contents.rstrip())

文件路径:在windows系统中,文件路径使用反斜杠
with open(‘text_file\filename.txt’) as file_object:
将文件在计算机中的准确位置告诉python,不用关心当前运行的程序存储在哪,此时文件路径为绝对路径。


file_path='C:\Users\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.rstrip())#消除每一行之后的空行

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

filename='pi_digits.txt'
with open(filename) as file_object:
	lines=file_object.readlines() #从文件中读取每一行,并将其存储在一个列表中
for line in lines:
	print(line.rstrip())

使用文件的内容

with open(filename) as file_object:
	lines=file_object.readlines() #从文件中读取每一行,并将其存储在一个列表中
pi_string=''
for line in lines:
	pi_string+=line.rstrip()
print(pi_string)
print(len(pi_string))

删除每行左边的空格可以使用strip()

pi_string+=line.strip()

读取文本文件时,python将其中的所有文本都解读为字符串,如果读取的是数字,并将其作为数值使用,需要使用函数int()转换为整数,或使用float()转换为浮点数。


包含一百万位的大型文件

for line in lines:
	pi_string+=line.strip()
print(pi_string[:52]+"…") #只打印小数点后50位
print(len(pi_string)) #打印字符串的长度

写入文件
将文本写入空文件

filename='programming.txt'
with open(filename,'w') as file_object:
	file_object.write("I love programming.")

写入多行

with open(filename,'w') as file_object:
	file_object.write("I love programming.")
	file_object.write("I love create new games")
函数write()不会再写入的文本末尾加换行符,如果写入多行需要自行制定换行符
with open(filename,'w') as file_object:
	file_object.write("I love programming.\n")
	file_object.write("I love create new games.\n")

附加到文件
如果要给文件添加内容,不是覆盖原有的内容,使用附加模式打开文件,写入到文件的行都将添加到文件末尾。


如果指定的文件不存在,python会创建一个空文件。


filename='programming.txt'
with open(filename,'a') as file_object:
	file_object.write("aaaaa.\n")
	file_object.write("bbbbb.\n")
异常

python使用被称为异常的对象来管理程序执行期间发生的错误,每当执行到错误,都会创建一个异常对象。


如果编写了处理该异常的代码,程序将会继续执行,如果未对异常进行处理,程序将停止,并显示一个traceback,其中包含有关异常的警告。



异常是使用try-except代码块处理的。



处理ZeroDivisionError异常

try:
	print(5/0)
except ZeroDivisionError:
	print("You can’t divide by zero!")

使用异常避免崩溃
如果程序能够妥善处理无效输入,就能再提示用户提供有效输入,不至于崩溃。


print("Give me two numbers, and I’ll divide them.")
print("Enter 'q' to quit.")
while True:
	first_number=input("input first number:")
	if first_number=='q':
		break
	second_number=input("second_number:")
	if second_number=='q':
		break
	answer=int(first_number)/int(second_number)
	print(answer)

将可能引发错误的代码放在try-except代码块中,可以提高这个程序抵御错误的能力。


while True:
	first_number=input("input first number:")
	if first_number=='q':
		break
	second_number=input("second_number:")
	try:
		answer=int(first_number)/int(second_number)
	except ZeroDivisionError:
		print("you can’t divide by 0")
	else:		#依赖于try代码块成功执行的代码放到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)

分析文本
分析文本中包含多少个单词,使用方法split(),根据字符串创建一个单词列表

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)
else:
	words=contents.split()  #计算文本包含多少个单词
	num_words=len(words)
	print("The file "+filename+" has about "+str(num_words)+" words.")

使用多个文件
先将程序的大部分代码移到一个函数中。


def count_words(filename):
	try:
		with open(filename) as f_obj:
			contents=f_obj.read()
	except FileNotFoundError:
		msg="sorry, the file"+filename+"does not exist."
		print(msg)
	else:
		words=contents.split()  #计算文本包含多少个单词
		num_words=len(words)
		print("The file"+filename+" has about "+str(num_words)+" words.")
filename='alice.txt'
count_words(filename)

filenames=['alice.txt','moby_dick.txt','little_women.txt']
for filename in filenames:
	count_words(filename)

并非捕获到异常都需要告诉用户,有时候希望程序发生异常后一声不吭。


try:
	…
except FileNotFoundError:
	pass			#不处理错误
else:
	…

存储数据

很多程序都要求用户输入某种信息,程序会把用户提供的信息存储在列表和字典等数据结构中,用户关闭程序时,几乎总是要保存他们提供的信息,一种简单的方式是使用模块json存储数据。


模块json可以将简单的python数据结构存储到文件中,并在程序再次运行时加载文件中的数据,还可以用json在python程序之间分享数据。


可以以JSON格式存储的数据与使用其他编程语言的人分析。


使用json.dump()和json.load()
json.dump()接受两个实参:要存储的数据和可用于存储数据的文件对象。


import json
numbers=[2,3,4,6,8]
filename='numbers.json'
with open(filename,'w') as f_obj:
	json.dump(numbers,f_obj)

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

import json
filename='numbers.json'
with open(filename) as f_obj:
	numbers=json.load(filename)
print(numbers)

保存和读取用户生成的数据
使用json保存用户生成的数据
remember_me.py

import json
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.py

import json
filename='username.json'
with open(filename) as f_obj:
	username=json.load(f_obj)
	print("welcome back, "+username+"!")

将两个程序合并到一起

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 back,"+username+"!")
else:
	print("Welcome back,"+username+"!")
重构

当代码能够运行,但是可以进一步改进,将代码划分为一系列完成具体工作的函数,称为重构。


重构可以让代码更清晰、更易于理解、更容易扩展。



重构remember.py

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()

重构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= nput(“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+"!")

greet_user()
测试代码

编写函数或类时,还可以编写测试,通过测试,可以确定代码面对各种输入都能够按照要求那样工作。


使用python模块unittest中的工具测试代码,编写测试用例,核实一系列输入都将得到预期输出。


单元测试和测试用例

python标准库中的模块unittest提供了代码测试工具,单元测试用于核实函数的某个方面没有问题;
测试用例是一组单元测试,这些单元测试一起核实函数在各种情形下的行为都符合要求。



良好的测试用例考虑到函数可能收到的各种输入,包含针对所有这些情形的测试。


全覆盖式测试用例包含一整套单元测试,涵盖了各种可能的函数使用方式。



最初只要针对代码的重要行为编写测试即可,等项目被广泛使用时再考虑全覆盖。


可通过的测试
测试函数name_function.py

def get_formatted_name(first,last):
	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):	#创建一个继承unittest.TestCase的类
	def test_first_last_name(self):
		formatted_name=get_formatted_name('janis','joplin')
		self.assertEqual(formatted_name,'Janis Joplin')#断言方法核实得到的结果是否与期望的结果一致
unittest.main()#让python运行这个文件中的测试

不能通过的测试

name_function.py
def get_formatted_name(first,middle,last):
	full_name=first+' '+middle+' '+last
	return full_name.title()

测试用例NamesTestCase 的函数test_first_last_name未通过
修改:将形参middle移到形参列表末尾

def get_formatted_name(first, last,middle=''):

添加新测试

import unittest	#导入模块
from name_function import get_formatted_name	#导入测试函数

class NamesTestCase(unittest.TestCase):	#创建一个继承unittest.TestCase的类

	def test_first_last_name(self):
		formatted_name=get_formatted_name('janis','joplin')
		self.assertEqual(formatted_name,'Janis Joplin')#断言方法核实得到的结果是否与期望的结果一致

	def test_first_middle_last_name(self):
		formatted_name=get_formatted_name('wolfgang','mozart','amadeus')
		self.assertEqual(formatted_name,'Wolfgang Mozart Amadeus')

unittest.main()#让python运行这个文件中的测试
测试类

编写针对类的测试
python的unittest.TestCase类提供的各种断言方法:

一个要测试的类
survey.py

class AnoymousSurvey():
	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("Suvery results:")
		for response in self.responses:
			print('-'+response)

为了证明AnoymousSurvey类能正确工作,编写一个使用它的程序
language_survey.py

from survey import AnoymousSurvey

question="What language did you first learn to speak?"
my_survey=AnoymousSurvey(question)

my_survey.show_question()
print("Enter 'q' at any time to quit.\n")
while True:
	response=input("Language:")
	if(response=='q'):
		break
	my_survey.store_response(response)

print("\nThank you to everyone who participated in the survey!")
my_survey.show_results()

测试AnoymousSurvey类
test_survey.py

import unittest
from survey import AnoymousSurvey

class TestAnoymousSurvey(unittest.TestCase):
	def test_stored_single_response(self):
	"""测试单个答案"""
		question=”What language did you first learn to speak?"
		my_survey=AnoymousSurvey(question)
		my_survey.store_response('English')
	
		self.assertIn('English',my_survey.responses)

	def test_stored_three_responses(self):
	"""测试三个答案"""
		question="What language did you first learn to speak?"
		my_survey=AnoymousSurvey(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()

unittest.TestCase类包含方法setUp(),只需创建这些对象一次,并在每个测试方法中使用他们。


如果TestCase类中包含方法setUp(),python将先运行它,再运行各个以test_开头的方法。


这样在每个测试方法中都可以使用方法setUp()中创建的对象了。


import unittest
from survey import AnoymousSurvey

class TestAnoymousSurvey(unittest.TestCase):

	def setUp(self):
		question="What language did you first learn to speak?"
		self.my_survey= AnoymousSurvey(question)
		self.responses=['English','Spanish','Mandarin']

	def test_stored_single_response(self):
	"""测试单个答案"""
		self.my_survey.store_response('English')
		self.assertIn(self.responses[0],self.my_survey.responses)

	def test_stored_three_responses(self):
	"""测试三个答案"""
		for response in self.responses:
			self.my_survey.store_response(response)
		
		for response in self.responses:
			self.assertIn(response,my_survey.responses)

unittest.main()

测试自己编写的类时,方法setUp()让测试方法编写起来更容易,可在setUp()方法中创建一系列实例并设置它们的属性,再在测试方法中直接使用这些实例,相比较于每个测试方法中都创建实例并设置属性容易。


参考书籍:《Python编程从入门到实践》

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/570828.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-09
下一篇 2022-04-09

发表评论

登录后才能评论

评论列表(0条)

保存