Python学习笔记-3

简介: 9.文件和异常1)从文件中读取数据randint():将两个整数作为参数,并随机返回一个位于这两个整数之间(含)的整数。choice():将一个列表或元组作为参数,并随机返回其中的一个元素

9.文件和异常

1)从文件中读取数据

with open('pi_digits.txt') as file_object:


contents = file_object.read()


要以任何方式使用文件,哪怕只是打印内容,都需要打开文件才能访问。


函数open()接一个参数,即要打开的文件的名称。Python将在当前执行的文件所在的目录中查找指定的文件。


open()打开文件后不需要关闭,系统会自动在合适时机将其关闭。自行调用close可能会在存在bug时导致close()未执行而没有关闭文件。未妥善关闭文件可能导致数据丢失或受损。


使用语句print(contents)后输出结果的末尾多了一个空行(如果鼠标指针在新启一行)。这是因为read()达到文件末尾时放回一个空字符串。要删除空行可以调用print(contents.rstrip())


open()参数中显示文件路径时一般使用斜杆(虽然Windows系统使用反斜杠),因为反斜杠会被识别为转义字符,当然也可以对每个反斜杠进行转义。如'text_files/filename.txt'或'text_files\\filename.txt'(此二者为相对路径)

绝对路径:'C:\\path\\to\\file.txt'

"""逐行读取"""
filename = 'pi_digits.txt'
with open(filename) as file_object:
    for line in file_object:
        print(line.rstrip())

读取文本文件时,Python将其中的所有文本都解读为字符串。如果要将其作为数值使用,就必须使用函数int()转化为整数或使用float()转化为浮点数。

""""判断生日是否在Π中"""
filename = 'pi_digits.txt'
pi_string = ''
with open(filename) as file_object:
    lines = file_object.readlines()
for line in lines:
    """将几行数字合为一个字符串"""
    pi_string += line.strip()
birthday = input("Enter your birthday,in the form mmddyy:")
if birthday in pi_string:
    print("Your birthday appears in the digits.")
else:
    print("your birthday does not appear in the digits.")

2)写入文件

filename = 'pi_digits1.txt'
with open(filename,'w') as file_object:
    file_object.write("Hello World!")

open()第二个实参为模式实参:


‘w’:以写入模式打开;


‘r’:以读取模式打开;


‘a’:以附加模式打开;(给文件添加内容而不是覆盖原有的内容)


‘r+’:以读写模式打开;


如果省略了模式实参,Python将以默认的只读模式打开文件。


如果写入的文件不存在将自动创建,如果指定的文件已经存在,将清空该文件的内容。


Python只能将字符串写入文本文件,要将数值数据存储到文本文件中,必须先使用函数str()使其转化为字符串格式。


函数write()不会在写入的文本末尾添加换行符,因此如果写入多行时没有指定换行符会导致两行连接在一起。


‘a’会将内容添加到文件末尾,同样不会有换行符。

3)异常

每当发生让Python不知所措的错误是,他都会创建一个一异常对象。如果你编写了处理该异常的代码,程序将继续运行,如果未对异常进行处理,程序将停止并显示traceback,其中包含有关异常的报告。

"""处理ZeroDivisionError异常"""
try:
    print(5/0)
except ZeroDivisionError:
    print("You can't divide by zero!")
else:
  print(answer)

将导致错误的代码行放在一个try代码块中。如果try代码块中的代码运行起来没有问题,Python将跳过except代码块;如果导致了错误将查找与之匹配的except代码块并运行其中的代码。如果try-except代码块后面还有其他代码,程序会接着运行。


有时候一些代码尽在try代码块成功执行时才需要运行,这些代码应放在else代码块中。(尝试某些代码,出现某些指定异常则执行对应except代码块,没有异常则运行else代码块)

FileNotFoundError异常:Python找不到要打开的文件时创建的异常。这个错误是函数open()导致的,因此要处理这个错误,必须将tr语句放在包含open()的代码行之前。

title = "Alice in Wonderland in"
print(title.split())

输出结果为['Alice', 'in', 'Wonderland', 'in']

def count_word(name):
    """计算一个文件大致包含多少个单词"""
    try:
        with open(name, encoding='utf-8') as f:
            contents = f.read()
    except FileNotFoundError:
        print(f"Sorry,the file {name} does not exist.")
    else:
        words = contents.split()#split可以根据一个字符串创建一个单词列表。 
        num_words = len(words)
        print(f"The file {name} has about {num_words} words.")
filenames = ['alice.txt', 'siddhartha.txt', 'moby_dick.txt', 'little_women.txt']
for filename in filenames:
    count_word(filename)

静默失败:捕获到异常后像什么都没有发生一样继续运行。只需要把except代码块的代码换成pass:

except FileNotFoundError:

pass

4)存储数据

用户关闭程序时。总是要保存他们提供的信息,一种简单的方是使用模块json(JavaScript Object Notation)来存储数据。模块json让你能够将简单的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()接受两个实参:要存储的数据,以及可用于存储数据的文件对象。数据的存储格式与Python中一样。

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

json.load()加载存储在其实参中的信息。

import json
# 如果以前存储了用户名,就加载它。
# 否则,提示用户输入用户名并存储它。
filename = 'username.json'
try:
    with open(filename) as f:
        username = json.load(f)
except FileNotFoundError:
    username = input("What is your name?")
    with open(filename, 'w') as f:
        json.dump(username, f)
        print(f"We will remember you when you come back,{username}!")
else:
    print(f"Welcome back,{username}!")


上述代码可进行重构,而得到更清晰且易于维护和扩展的代码,如下:

import json
def get_stored_username():
    """如果存储了用户名,就获取它"""
    filename = 'username.json'
    try:
        with open(filename) as f:
            username = json.load(f)
    except FileNotFoundError:
        return None
    else:
        return username
def get_new_username():
    """提示用户输入用户名"""
    username = input("What is your name?")
    filename = 'username.json'
    with open(filename, 'w') as f:
        json.dump(username, f)
    return username
def greet_user():
    """"问候用户,并指出其名字"""
    username = get_new_username()
    if username:
        print(f"Welcome back,{username}!")
    else:
        username = get_new_username()
        print(f"We will remember you when you come back,{username}!")
greet_user()

10.测试代码

1)测试函数

Python提供了了一种自动测试函数输出的高效方式(不再需要每次修改代码后自行输入数据测试),由标准库中的模块unittest提供。

单元测试用于核实函数的某个方面没有问题。测试用例是一组单元测试,它们一道核实在各种情形下的行为全部符合要求。良好的测试用例考虑了函数可能收到的各种输入,包含针对所有这些情形的测试。

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

"""name_function"""
def get_formatted_name(first, last, middle=""):
    """生成姓名"""
    if middle:
        full_name = f"{first} {middle} {last}"
    else:
        full_name = f"{first} {last}"
    return full_name.title()
import unittest
from name_function import get_formatted_name
class NameTestCase(unittest.TestCase):
    """测试name_function.py"""
    def 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')
if __name__ == '__main__':
    unittest.main()

运行该程序时,所有以test_打头的方法都将自行运行。


创建一个类,用于包含一系列针对要测试函数的单元测试。


这个类可以随便命名(最好以Test起始),但必须继承unittest.TextCase类,这样Python才知道如何运行你编写的测试。


self.assertEqual(formatted_name, 'Janis Joplin')是unittest类最有用的功能之一:断言方法。


断言方法核实得到的结果是否与期望的结果一致。意思是将formatted_name的值与字符串’Janis Joplin’进行比较。


很多测试框架都会先导入测试文件再运行,导入文件时,解释器将在导入的同时执行它。


if代码块检查特殊变量__name__,这个变量时在程序执行时设置的。如果这个文件为主程序执行时,该变量将被设置为__main__。在这里,调用unittest.main()来运行测试用例,如果这个文件被测试框架导入,变量__name__的值将不是__main__,因此不会调用unittest.main()


若输出结果为OK则表示该测试用例中的单元测试都通过了,未通过测试则返回FAILED。


2)测试类

六个常用的断言方法(只能在继承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"""
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 responses:
            print(f"-{response}")
import unittest
from survey import AnonymousSurvey
class TestAnonymousSurvey(unittest.TestCase):
    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_response(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()

在该测试中,每个测试方法都创建了一个AnonymousSurvey的实例,并在每个方法中都创建了答案。

然而调用unittest.TestCase中的方法setUp()可以让我们只需要创建这些对象一次,就可以在每个测试方法中使用。

如果在测试方法中包含了方法setUpI(),Python将先运行它,再运行每个以test_打头的方法,这样在每个测试方法中都可以使用在方法setUp()中创建的对象。如下:

import unittest
from survey import AnonymousSurvey
class TestAnonymousSurvey(unittest.TestCase):
    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_response(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()

方法setUp()创建了一个调查对象以及一个答案列表,存储这两样东西的变量名包含了前缀self(即存储在属性中),因此可在这个类的任何地方使用。


的实例,并在每个方法中都创建了答案。


然而调用unittest.TestCase中的方法setUp()可以让我们只需要创建这些对象一次,就可以在每个测试方法中使用。

如果在测试方法中包含了方法setUpI(),Python将先运行它,再运行每个以test_打头的方法,这样在每个测试方法中都可以使用在方法setUp()中创建的对象。如下:

import unittest
from survey import AnonymousSurvey
class TestAnonymousSurvey(unittest.TestCase):
    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_response(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()

方法setUp()创建了一个调查对象以及一个答案列表,存储这两样东西的变量名包含了前缀self(即存储在属性中),因此可在这个类的任何地方使用。


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


-----------------------------------整理自《Python编程 从入门到实践(第二版)》


相关文章
|
2月前
|
网络协议 Java Linux
PyAV学习笔记(一):PyAV简介、安装、基础操作、python获取RTSP(海康)的各种时间戳(rtp、dts、pts)
本文介绍了PyAV库,它是FFmpeg的Python绑定,提供了底层库的全部功能和控制。文章详细讲解了PyAV的安装过程,包括在Windows、Linux和ARM平台上的安装步骤,以及安装中可能遇到的错误和解决方法。此外,还解释了时间戳的概念,包括RTP、NTP、PTS和DTS,并提供了Python代码示例,展示如何获取RTSP流中的各种时间戳。最后,文章还提供了一些附录,包括Python通过NTP同步获取时间的方法和使用PyAV访问网络视频流的技巧。
339 4
PyAV学习笔记(一):PyAV简介、安装、基础操作、python获取RTSP(海康)的各种时间戳(rtp、dts、pts)
|
2月前
|
Python
Socket学习笔记(二):python通过socket实现客户端到服务器端的图片传输
使用Python的socket库实现客户端到服务器端的图片传输,包括客户端和服务器端的代码实现,以及传输结果的展示。
152 3
Socket学习笔记(二):python通过socket实现客户端到服务器端的图片传输
|
2月前
|
JSON 数据格式 Python
Socket学习笔记(一):python通过socket实现客户端到服务器端的文件传输
本文介绍了如何使用Python的socket模块实现客户端到服务器端的文件传输,包括客户端发送文件信息和内容,服务器端接收并保存文件的完整过程。
169 1
Socket学习笔记(一):python通过socket实现客户端到服务器端的文件传输
|
2月前
|
关系型数据库 MySQL 数据库
Mysql学习笔记(四):Python与Mysql交互--实现增删改查
如何使用Python与MySQL数据库进行交互,实现增删改查等基本操作的教程。
69 1
|
2月前
|
Ubuntu Linux Python
Ubuntu学习笔记(六):ubuntu切换Anaconda和系统自带Python
本文介绍了在Ubuntu系统中切换Anaconda和系统自带Python的方法。方法1涉及编辑~/.bashrc和/etc/profile文件,更新Anaconda的路径。方法2提供了详细的步骤指导,帮助用户在Anaconda和系统自带Python之间进行切换。
103 1
|
2月前
|
索引 Python
Python学习笔记编程小哥令狐~持续更新、、、(上)
Python学习笔记编程小哥令狐~持续更新、、、(上)
51 2
|
2月前
|
存储 Python
Python学习笔记编程小哥令狐~持续更新、、、 (下)
Python学习笔记编程小哥令狐~持续更新、、、 (下)
34 1
|
2月前
|
存储 Python
【免费分享编程笔记】Python学习笔记(二)
【免费分享编程笔记】Python学习笔记(二)
44 0
【免费分享编程笔记】Python学习笔记(二)
|
2月前
|
Java 编译器 Go
Python学习笔记--- day01计算机基础和环境搭建(一)
Python学习笔记--- day01计算机基础和环境搭建(一)
43 2
|
2月前
|
程序员 编译器 Python
Python学习笔记--- day01计算机基础和环境搭建(二)
Python学习笔记--- day01计算机基础和环境搭建(二)
49 1