B站python入门学习---第一阶段第八~九章 文件操作、异常、模块与包
第八章 文件
一、文件的读取操作
文件操作主要包括:打开、关闭以及读和写。
#文件打开命令有三个参数 #第一个参数为文件路径,可以用相对路径,也可以是绝对路径 #第二个参数为模式参数,r表示只读,第三个参数为文件编码格式 f = open("test1.txt", "r", encoding="UTF-8") #read()方法中可以设置一次性读取的字节数 print(f"读取两个字节的结果为{f.read(2)}") #继续读取的话会从前面已读完的位置再继续开始 print(f"读取两个字节的结果为{f.read(2)}") print(f"继续读取完毕的结果为{f.read()}") #操作完成需要关闭文件 f.close() #继续打开 f = open("test1.txt", "r", encoding="UTF-8") #readlines()是按逐行读取的方式,内容逐行存储在列表中 lines = f.readlines() for i in lines: print(i) #操作完成关闭文件 #另外还有readline()方法,只读一行 f = open("test1.txt", "r", encoding="UTF-8") print(f"第一次使用readline()读取结果为{f.readline()}") print(f"第二次使用readline()读取结果为{f.readline()}") print(f"继续使用readlines()读取结果为{f.readlines()}") #结束记得关闭文件 f.close()
为避免忘记关闭文件,可以通过with open方式打开文件:
with open("test1.txt", "r", encoding="UTF-8") as f: #其实也可以直接用for lines in f,这种方式每次遍历也是得到一行数据 for lines in f.readlines(): print(lines)
小练习:
''' 读取指定文件内容 并统计itheima出现的次数 ''' with open("test2.txt", "r", encoding="UTF-8") as f: text = f.read() print(text) counter = text.count("itheima") print(f"itheima在文本中总共出现了{counter}次。")
二、文件的写入操作
#文件写入 #1、同样先打开文件,如果文件不存在,则新创建一个文件,并写入内容 #如果文件已存在,w模式会覆盖原有内容 f = open("test3.txt", "w", encoding="UTF-8") #2、写入,实际这里是写在内存的 f.write("python learning!") #3、刷新,将内存中内容刷新到文件中 f.flush() #4、关闭文件,close()方法自带flush功能 f.close()
三、文件的追加操作
#文件追加 #1、同样先打开文件,如果文件不存在,则新创建一个文件,并写入内容 #如果文件已存在,a模式会在原有内容后面追加写入内容 f = open("test3.txt", "a", encoding="UTF-8") f.write("\npython learning!222") f.close()
综合案例
''' 读取bill.txt文件 将文件写出到bill.txt.bak文件,作为备份 同时,将文件内标记为测试的数据正常丢弃 ''' f_resouce = open("bill.txt", "r", encoding="UTF-8") f_aim = open("bill.txt.bak", "w", encoding="UTF-8") for line in f_resouce: if "测试" in line: continue f_aim.write(line) f_resouce.close() f_aim.close()
第九章 异常处理,模块和包
一、异常处理
之前学习到编程中异常处理的时候往往不是太明白,为何需要异常处理这个机制,多调试不就可以了么。现在看,这就是程序设计健壮性的体现,何况现在软件工程设计中大量的分工协作,你即便能保证你代码的完美,你不能确保你导入模块、函数等文件代码的完美,所以提供异常处理确实是一种程序健壮性的实现;另外一种情况,一段代码实现了N种功能,而我在某个时刻只关注其中一种功能的实现,但调试的时候总在其他部分出现BUG,那么也可以通过异常处理机制来暂时“屏蔽”或者代替这个BUG代码段。
''' 演示异常的处理 ''' #基本捕获语法 try: f = open("test_except.txt", "r", encoding="UTF-08") except: print("出现异常了!")
一般来说,异常只处理逻辑类错误,语法类,比如多了个标点,少了括号等语法类错误,异常处理不适用:
#语法错误,会报错,无法异常处理 try: print("ABC" #少一个括号 except: print("ERROR!")
在知道某段代码可能出现BUG,而且大概率可以判断其异常类型的话可以指定异常种类,并通过as语句获取其更多信息。
#捕获指定异常 try: print(name) except NameError as e: print("异常出现!") print(e) try: print(1/0) except ZeroDivisionError as e: print("异常出现!") print(e)
as之后的e对象是异常类的对象,其类型就是异常,但其实质内容就是之前的报错文本信息,可以通过str()转换为字符串格式(当然可以不转换,因为直接打印也可以显示)
try: print(1/0) except ZeroDivisionError as e: print("异常出现!") print(f"出现了{type(e)}类异常,提示信息为{e}") print(str(e)+"135") #除了可以直接打印之外,如要对e进行字符串操作需要先str转换
捕获各种异常类型的指定类型Exception
#捕获所有类型异常 try: 1/0 #第一个除0异常 except Exception as e: print(f"出现了{type(e)}类的异常,提示信息为{e}")
如果不确定是某种类型,但知道是几种类型范围之内,可以如下处理:
#捕获多种类型的异常 try: name #第一个除0异常 except (ZeroDivisionError, NameError) as e: print(f"出现了{type(e)}类的异常,提示信息为{e}")
除了try-except的形式,还可以通过else来提供没有异常情况下的处理代码,而finally则是无论异常是否发生都必须执行的代码
#else和finally的用法 try: f = open("test_exception.txt", "r", encoding="UTF-8") #只读方式打开一个不存在的文件会产生异常 except Exception as e5: print(f"出现了{type(e5)}类的异常,提示信息为{e5}") f = open("test_exception.txt", "w", encoding="UTF-8") #通过写入模式打开则会新建一个文件 else: print("没有异常出现!") #没有异常出现情况下的代码 finally: print("无论有无异常都必须执行的代码放到finally中!") print(f.close()) #对于本例,无论异常是否发生,关闭文件操作都是必要的
异常的传递,其实就是指部分代码调用异常代码所在模块的情况
def func1(): print("Function1 start...") num = 1/0 #此处为异常源头 print("Function2 finished.") def func2(): print("Function2 start...") func1() #此处调用异常所在代码块 print("Function2 finished.") def main(): try: func2() #此处继续调用“调用异常代码”的代码块 except Exception as e: print("Error!") print(e) finally: print("All Finished!") main() #函数执行时候捕捉和处理异常
二、模块和包
1、模块:Python中一个以.py结尾的文件就是一个模块,模块可以被其他代码引用,实现代码的复用;
2、包:存放模块的文件夹,Python3.3之前的版本,包中必须要包括__init__.py文件其他代码猜可以导入该包内模块,__init__.py文件一般提供导入操作时的一些执行功能,当然也可以为空文件;Python3.3开始__init__文件不是必须;
3、库:即为各类包的合集。
#从p1包中导入a,b两个模块,会先执行p1包中的__init__文件
from p1 import a, b
print(1)
#再分别打印导入包中模块内定义的变量
print(a.a)
print(b.b)
一般来说,模块内只做类、函数、变量的定义,示例mod.py文件内容如下:
s = "If Comrade Napoleon says it, it must be right." a = [100, 200, 300] def foo(arg): print(f'arg = {arg}') class Foo: pass
上面的mod.py只做了定义,执行该代码只在内存空间中创建了上述对象,而并不会有结果输出;
有时候我们不光要定义,也要模块可以作为脚本执行,那么在代码中需要增加执行代码,如下:
s = "If Comrade Napoleon says it, it must be right." a = [100, 200, 300] def foo(arg): print(f'arg = {arg}') class Foo: pass #如下增加执行代码 print(s) print(a) foo("Tuesday") x = Foo() print(x)
但是当我们把这个文件当作一个模块,在其他文件中引用时,同样的结果会输出出来,这让不是我们需要的结果。比如:
import mod print("This is main Function.") print(mod.s) print(mod.a)
如上代码先执行导入模块的时候会把模块代码先执行,再执行本模块内的代码,执行结果如下:
If Comrade Napoleon says it, it must be right. [100, 200, 300] arg = Tuesday <mod.Foo object at 0x0000021A41067CB0> This is main Function. [100, 200, 300] If Comrade Napoleon says it, it must be right.
这显然不是我们需要的效果,我们希望模块文件作为脚本时候可以独立执行,但如果作为被导入的模块使用它本身的操作代码可以不执行(但其定义的对象依然可以被导入使用),这就需要增加 __name__ == __main__的判断
如果成立,则说明模块被单独执行了,此时该模块的name值就是__main__,如果模块是被导入才执行,那它的模块name值就是其文件名。如下mod.py示例:
s = "If Comrade Napoleon says it, it must be right." a = [100, 200, 300] def foo(arg): print(f'arg = {arg}') class Foo: pass print(f"此时本模块的__name__为{__name__}。") if __name__ == "__main__": print("Exuting as standalone script!") print(s) print(a) foo("Tuesday") x = Foo() print(x)
执行上述模块输出结果如下:
此时本模块的__name__为__main__。 Exuting as standalone script! If Comrade Napoleon says it, it must be right. [100, 200, 300] arg = Tuesday <__main__.Foo object at 0x000002937CC07CB0>
如果main.py导入mod.py,main文件如下:
import mod print("This is main Function.") print(mod.s) print(mod.a)
执行结果如下:
此时本模块的__name__为mod。 This is main Function. If Comrade Napoleon says it, it must be right. [100, 200, 300]
关于导入内容,在使用from X import Y格式的时候,如果Y表示为“*”,即表示导入X中所有模块/对象/变量等。这里的导入范围是可以在X模块中__all__列表设置的。
#本模块定义了三个对象:列表,字符串,函数。 #通过__all__设置from impot *情况下的可导入对象为mylist和myfunc __all__ = ["mylist", "myfunc"] mylist = [1, 2, 3] mystr = "Hello S!" def myfunc(): print("This is a function named myfunc in module c.")
在外部模块导入上模块时的执行情况:
from p1.c import * #因为p1.c模块中__all__的设置,可以访问mylist和myfunc print(mylist) myfunc() #但不可以访问mystr,下句会报错 #print(mystr)
__all__的设置仅对from X import *的情况有作用,对于未列入__all__列表内的对象,仍然可以通过名称导入。
上述为from import *导入模块中对象的限定操作,对于包的导入,同样可以设置包内__init__文件内__all__来指定可导入的包内模块。
p1包中有__init__文件和a,b,c模块,其中__init__文件内容:
#设置p1包中__init__文件中的__all__来限定可通过from import *导入的模块 __all__ = ["a", "b"] print("This is Package1.")
主程序代码如下:
#因为p1中__init__内部__all__参数的设置,下面导入代码只能导入p1中的a,b from p1 import * #可以正常访问p1下的a,b模块 print(a.a) print(b.b) #但无法使用p1下的c模块 #print(c.mylist)
*异常、模块、包:综合案例 自定义工具包
创建一个自定义包,名称为:my_utils
包内提供两个模块:
1、str_util.py模块(字符串相关工具):
函数:str_reverse(s),接受传入字符串,将字符串反转返回
函数:substr(s, x, y),按照下标x,y对字符串s进行切片
2、file_util.py模块(文件处理相关工具):
函数:print_file_info(file_name),接受传入文件的路径,打印文件内容,如果文件不存在则捕获异常输出提示信息,通过finally关闭文件
函数:append_to_file(file_name, data),接受文件路径以及传入数据,将数据追加写入到文件中
""" str_util.py模块(字符串相关工具): """ def str_reverse(s): """ 接受传入字符串,将字符串反转返回 """ return s[::-1] def substr(s, x, y): """ 按照下标x,y对字符串s进行切片 """ return s[x:(y+1)] #测试代码 if __name__ == "__main__": print(str_reverse("ILOVEPython!")) print(substr("ILOVECHINA", 2, 9))
""" file_util.py模块(文件处理相关工具): 函数:print_file_info(file_name), 函数:append_to_file(file_name, data) """ def print_file_info(file_name): """ 接受传入文件的路径,打印文件内容,如果文件不存在则捕获异常输出提示信息 通过finally关闭文件 """ try: f = open(file_name, "r", encoding="UTF-8") except Exception as e: print(f"文件{file_name}不存在,报错信息为{e}。") else: print(f"文件内容为:\n{f.read()}") f.close() def append_to_file(file_name, data): """ 接受文件路径以及传入数据,将数据追加写入到文件中 :param file_name: :param data: :return: """ f = open(file_name, "a", encoding="UTF-8") f.write(data) f.close()
浙公网安备 33010602011771号