【零基础学Python】06-Python模块和包、异常处理、文件常用操作
✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨
🎯你正在阅读「Python 从零摸索日记」系列文章🎯
✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨🔥弹简特 个人主页
❄️个人专栏直通车:
- 💻软件测试入门记
- 📱野生测试修炼手册 | APP 专项测试笔记
- 🔌接口测试从入门到跑路
- ☕一个后端的 JavaEE 续命指南
- 🛜网络原理续命手册
- 🐍Python 从零摸索日记
- ☕Java项目-轻聊
- ☕Java项目-企悦抽
✨靠热爱去书写自己,靠勇敢去书写生活!
✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨
🌟 博主简介:
文章目录:
- 一、前言
- 二、模块、包、库
- 1、概念
- 1.1 模块
- 1.2 包
- 1.3 库
- 2、导入模块的常用方式
- 2.1 方式1:`import 模块名`
- 2.2 方式2:`from 模块名 import 函数名/变量名`
- 2.3 方式3:`from 模块名 import *`
- 2.4 给模块或函数起别名(`as`)
- 3、自定义模块的创建和导入
- 3.1 创建自定义模块
- 3.2 导入自定义模块
- 4、自定义包的创建和导入
- 4.1 创建包的结构
- 4.2 导入包中的模块
- 4.3 关于 `__init__.py` 的作用
- 5、注意事项和常见错误
- 5.1 命名规则
- 5.2 导入路径问题
- 5.3 循环导入
- 5.4 `import` 和 `from ... import ...` 的区别
- 三、异常处理
- 1、什么是异常?
- 2、怎么捕获异常?(try-except-else-finally)
- 3、捕获特定类型的异常
- 4、异常的传递
- 四、文件操作
- 1、操作文件的三个步骤
- 2、文件的打开模式
- 3、读取文件内容(`read`, `readlines`, `readline`)
- 4、写入文件(`w` 覆盖,`a` 追加)
- 5、二进制文件操作(图片、音频等)
- 6、文件常用操作(删除文件、删除文件夹)
- 五、写在最后
一、前言
老铁们,本文带你理清模块、包、库的层级关系,掌握导入技巧、异常捕获与文件操作。从零实战,轻松跨越新手进阶门槛。
二、模块、包、库
1、概念
1.1 模块
一句话解释:
一个.py文件就是一个模块。模块里可以写变量、函数、类等。
生活类比:
模块就像一本“菜谱”的其中一页。这一页专门记录“鱼香肉丝”的做法(变量、函数、类等)。
例子:
你新建一个文件叫tools.py,里面写:
# tools.py 这个文件就是一个模块name="计算器"defadd(a,b):returna+bdefmultiply(a,b):returna*b这个tools.py就是一个模块。
1.2 包
一句话解释:
一个包含多个.py模块的文件夹,并且这个文件夹里必须有一个__init__.py文件(可以是空的),这个文件夹就叫做包。
生活类比:
包就像一个“菜谱文件夹”,里面有好多页(模块),每页一个菜。__init__.py就像文件夹的封面,标记这是一个包。
例子:
my_package/# 这是一个包(文件夹)__init__.py# 必须存在(可以是空文件)math_tools.py# 模块1string_tools.py# 模块21.3 库
一句话解释:
库是一个更大的概念,通常指多个包集合在一起,提供一系列相关功能。比如 Python 标准库(os、sys、random等)、第三方库(requests、numpy、pandas)。
生活类比:
库就像一个“大图书馆”,里面有好多菜谱文件夹(包),还有很多其他功能的书。
注意:
在口语中,可能很多人会把“模块”、“包”、“库”混用,但我们得要知道它们层级关系:
模块(一个文件) < 包(一个文件夹+多个文件) < 库(多个包)
2、导入模块的常用方式
Python 有很多自带的模块(标准库),不需要安装,直接import就能用。
2.1 方式1:import 模块名
使用格式:模块名.函数名()或模块名.变量名
例子:使用random模块生成随机数
importrandom num=random.randint(1,10)# 生成1到10之间的随机整数print(num)2.2 方式2:from 模块名 import 函数名/变量名
这样导入后,可以直接用函数名,不需要加模块名前缀。
fromrandomimportrandint num=randint(1,10)# 直接写函数名print(num)导入多个方法或者变量:from random import randint, choice, shuffle
2.3 方式3:from 模块名 import *
导入模块中的所有内容(不推荐,容易命名冲突)。
fromrandomimport*num=randint(1,10)print(choice(["苹果","香蕉"]))2.4 给模块或函数起别名(as)
当模块名太长,或者你自己想换个名字,用as取别名。
importrandomasr num=r.randint(1,10)# 用别名 rprint(num)也可以给函数起别名:
fromrandomimportrandintasri num=ri(1,10)print(num)注意:原名randint失效,只能用新名字ri。
3、自定义模块的创建和导入
3.1 创建自定义模块
假设在当前目录下新建一个文件mymodule.py,里面写:
# mymodule.pyname="张三"defsay_hello():print("你好,我是自定义模块的函数")3.2 导入自定义模块
在同一目录下新建一个文件main.py,然后导入mymodule:
方式1:import 模块名
importmymoduleprint(mymodule.name)# 输出:张三mymodule.say_hello()# 输出:你好,我是自定义模块的函数方式2:from 模块名 import 变量/函数
frommymoduleimportname,say_helloprint(name)# 直接使用变量say_hello()# 直接调用函数方式3:from 模块名 import *
frommymoduleimport*print(name)say_hello()注意:Python 导入模块时,会执行模块中的代码(比如打印语句、定义函数等)。但一般模块里只放定义,不放主动执行的代码(除了测试)。
4、自定义包的创建和导入
4.1 创建包的结构
假设我们想创建一个包叫mypackage,里面有两个模块:module_a.py和module_b.py。
步骤:
- 新建一个文件夹,叫
mypackage。 - 在文件夹里新建一个空文件
__init__.py(Python 识别包必须要有这个文件,可以是空的)。 - 在文件夹里新建
module_a.py和module_b.py。
文件夹结构:
当前目录/ ├── main.py# 我们用来测试导入的文件└── mypackage/# 这是一个包├── __init__.py# 空文件├── module_a.py └── module_b.pymodule_a.py内容:
# module_a.pyname_a="模块A"deffunc_a():print("我是模块A的函数")module_b.py内容:
# module_b.pyname_b="模块B"deffunc_b():print("我是模块B的函数")4.2 导入包中的模块
在main.py中,你可以用以下几种方式导入:
方式1:导入整个模块(需要加包名.模块名)
importmypackage.module_aprint(mypackage.module_a.name_a)mypackage.module_a.func_a()方式2:from 包名 import 模块名
frommypackageimportmodule_aprint(module_a.name_a)module_a.func_a()方式3:from 包名.模块名 import 具体内容
frommypackage.module_aimportname_a,func_aprint(name_a)func_a()方式4:from 包名.模块名 import *
frommypackage.module_aimport*print(name_a)func_a()4.3 关于__init__.py的作用
__init__.py。它的作用:
- 告诉 Python 这个文件夹是一个包,可以被导入。
- 可以在里面写代码,当你
import mypackage时会自动执行。 - 可以控制
from mypackage import *会导入哪些模块(通过定义__all__列表)。
通常我们初学者可以暂时只放一个空文件。
5、注意事项和常见错误
5.1 命名规则
模块名、包名、变量名、函数名都要符合标识符命名规则:
字母、数字、下划线组成,不能数字开头,不能是关键字(如if、for、import),区分大小写。
5.2 导入路径问题
Python 查找模块的路径包括:
- 当前脚本所在目录
- 环境变量
PYTHONPATH - 标准库路径
- 第三方库安装路径
如果自定义模块不在当前目录,需要添加路径或用相对导入(以后讲)。
5.3 循环导入
不要出现a.py导入b.py,同时b.py又导入a.py,会导致错误。
例如:
5.4import和from ... import ...的区别
import 模块名:需要写模块名.xxx,不会污染当前命名空间。from 模块名 import xxx:直接使用xxx,但如果有同名变量会覆盖。
推荐:一般用import 模块名更清晰;只导入少数常用函数时可以用from ... import ...。
三、异常处理
1、什么是异常?
一句话解释:
你写的代码在运行时发生了错误(比如变量没定义、除以零、文件不存在),Python 就会“抛出一个异常”,程序会崩溃并打印一堆红色错误信息。
生活类比:
你让朋友去拿“冰箱里的蛋糕”,但冰箱里根本没有蛋糕。朋友就会回来跟你说“没有蛋糕啊!”——这个“没有蛋糕”就是异常。
最简单的异常例子:
print(a)# a 这个变量没定义过运行后你会看到类似这样的信息:
Traceback:异常追溯,告诉你错误发生的路径。File "xxx", line 1:哪个文件的第几行。NameError: name 'a' is not defined:异常类型和具体原因。
这些异常信息构造就是告诉你:异常信息包括执行路径、文件行号、错误类型和原因。看懂这些信息就能快速定位 bug。
2、怎么捕获异常?(try-except-else-finally)
如果你的程序可能因为用户输入错误、文件不存在等发生异常,你不想让程序崩溃,而是想“优雅地处理”这个错误(比如提示用户重新输入),这时就用try...except。
基本结构:
try:# 这里放可能会出错的代码except:# 如果 try 中出了异常,就执行这里的代码(程序不会崩溃)else:# 如果 try 中没有出异常,就执行这里的代码(可选)finally:# 不管有没有异常,最后都会执行这里的代码(可选,常用于关闭文件、释放资源)例如:
try:print("开始尝试执行代码")num=int(input("请输入一个数字:"))# 如果用户输入的不是数字,会触发 ValueErrorresult=10/num# 如果用户输入 0,会触发 ZeroDivisionErrorprint("计算结果是:",result)except:print("出错了!可能是输入的不是数字,或者除以了零。")else:print("没有发生异常,恭喜!")finally:print("不管有没有异常,我都会执行。")执行情况模拟:
用户输入
5(正常)→ 输出:开始尝试执行代码 计算结果是: 2.0 没有发生异常,恭喜! 不管有没有异常,我都会执行。用户输入
0(除以零)→ 输出:开始尝试执行代码 出错了!可能是输入的不是数字,或者除以了零。 不管有没有异常,我都会执行。用户输入
abc(不是数字)→ 输出类似上面。
关键点:
try中一旦发生异常,立刻跳转到except,try中剩余代码不再执行。except只捕获异常,不解决异常根源(只是让你有机会做补救措施,比如提示重新输入)。else只有在try完全没异常时才执行。finally无论如何都执行,非常适合做清理工作(比如关闭文件)。
3、捕获特定类型的异常
上面的except:会捕获所有异常,但有时候你想针对不同异常做不同处理,可以写多个except。
try:num=int(input("输入数字:"))result=10/numexceptValueError:print("你输入的不是合法数字!")exceptZeroDivisionError:print("不能除以零!")exceptExceptionase:# 捕获其他所有异常,e 是异常对象print("未知错误:",e)else:print("结果是",result)finally:print("结束")建议:写代码时先不要加try,先让程序崩溃,看清楚是什么异常类型(比如ValueError、ZeroDivisionError),然后再用对应的except去捕获它。
4、异常的传递
一句话解释:
如果函数 A 调用函数 B,函数 B 调用函数 C,在 C 中发生了异常且没有捕获,那么这个异常会一层一层往外传,直到被某个try...except捕获,如果一直没捕获,程序就崩溃。
例子:
deffunc1():print("func1 开始")func2()# 调用 func2deffunc2():print("func2 开始")print(x)# x 没定义,会触发 NameErrordefmain():try:func1()exceptNameError:print("捕获到了 NameError,程序没有崩溃")main()输出:
func1 开始 func2 开始 捕获到了 NameError,程序没有崩溃关键点:
- 异常会沿着调用链往回传递,直到被
try...except接住。 - 如果最外层也没接,程序就崩溃并打印 Traceback(那个红色错误信息)。
- 利用这个特性,你可以在合适的地方统一处理异常,而不是每个函数内部都写
try。
四、文件操作
1、操作文件的三个步骤
- 打开文件:
open(文件路径, 模式, encoding='编码') - 读/写文件:
.read()、.write()、.readlines()等 - 关闭文件:
.close()(释放系统资源)
生活类比:
打开冰箱(打开文件),拿一瓶饮料(读或写),关上冰箱门(关闭文件)。不关门的话,冰箱会一直耗电(占用系统资源)。
2、文件的打开模式
| 模式 | 含义 | 文件不存在时 |
|---|---|---|
'r' | 只读(默认) | 报错FileNotFoundError |
'w' | 只写,会覆盖原有内容 | 创建新文件 |
'a' | 追加,在文件末尾写入 | 创建新文件 |
'rb' | 二进制只读(图片、视频等) | 报错 |
'wb' | 二进制只写,会覆盖 | 创建新文件 |
'ab' | 二进制追加 | 创建新文件 |
注意:文本文件(.txt)一般指定encoding='utf-8',二进制文件(图片、音频)不能指定encoding。
3、读取文件内容(read,readlines,readline)
假设有一个test.txt文件,内容为:
你好,这里是 零基础学Python园地方法1:.read()— 一次性读取全部内容(字符串)
file=open('text.txt','r',encoding='utf-8')content=file.read()print(content)# 输出两行文字file.close()方法2:.readlines()— 一次性读取全部,按行返回列表(每行末尾有\n)
file=open('text.txt','r',encoding='utf-8')lines=file.readlines()print(lines)# 输出:['你好,这里是\n', '零基础学Python园地']# 去除换行符print('--'*100)# 首先使用一个列表,到时候存储去除换行之后的数据clean_lines=[]# 遍历返回的linesforiinlines:clean_lines.append(i.strip())print(clean_lines)# 输出:['你好,这里是', '零基础学Python园地']file.close()方法3:.readline()— 一次读取一行,多次调用读取下一行
file=open('text.txt','r',encoding='utf-8')line1=file.readline()# 第一行line2=file.readline()# 第二行print(line1,end='')# 不额外加换行print(line2,end='')file.close()注意:.read()和.readlines()适合小文件;大文件建议用循环.readline()或直接for line in file:。
4、写入文件(w覆盖,a追加)
覆盖写入 ('w'):
文件存在则清空原内容,不存在则新建。
file=open('output.txt','w',encoding='utf-8')file.write("第一行\n")# \n 表示换行file.write("第二行")file.close()追加写入 ('a'):
在文件末尾追加内容,不覆盖原有内容。
file=open('output.txt','a',encoding='utf-8')file.write("\n新增的一行")file.close()5、二进制文件操作(图片、音频等)
不能直接'r'或'w'去读写图片,因为图片是二进制数据。要用'rb'(读二进制)和'wb'(写二进制)。
例子:复制图片
接下来使用文件的读取加写入,将这个文件拷贝一份到output目录下,注意前提得先有output这个目录
代码如下:
# 打开原图(二进制读)# 打开原图(二进制读)withopen('srcpic/1.jpg','rb')assrc:data=src.read()# 写入新文件(二进制写)withopen('output/1_copy.jpg','wb')asdst:dst.write(data)解释疑问:为什么第二个中可以使用第一个的局部变量?
只有函数、类、模块才会创建新的作用域。像with、if、for、while这些语句块,不会创建独立的作用域。
所以,你在第一个 with 块里定义的变量 data,其实是属于它所在的函数或全局作用域。第二个 with 块自然也能访问到它。
结果:
什么是with open(...) as 变量:?
这叫“上下文管理器”,它会在代码块执行完后自动关闭文件,即使中间发生异常也会关闭。你就不需要手动写.close()了,非常推荐使用。
用法:
withopen('rap.txt','r',encoding='utf-8')asf:content=f.read()# 这里文件已经自动关闭,不需要 f.close()6、文件常用操作(删除文件、删除文件夹)
需要导入os和shutil模块。
- 删除文件:
os.remove('文件路径') - 删除空文件夹:
os.rmdir('文件夹路径')(只能删空的) - 删除非空文件夹(递归删除,慎用!):
shutil.rmtree('文件夹路径')
importosimportshutil# 删除单个文件os.remove('test.txt')# 删除空文件夹os.rmdir('empty_folder')# 删除非空文件夹(危险,删了找不回)shutil.rmtree('not_empty_folder')注意:shutil.rmtree非常危险,没有回收站功能,生产环境慎用。
五、写在最后
能坚持看到最后的朋友,属实是真爱学编程了,先歇会儿眼睛放松一下~
很多同学刚开始学Python,都不知道它到底能干啥。还是简单跟大伙唠唠:
可以做自动化测试、写办公脚本解放双手、爬虫采集数据、做数据分析、开发小工具、甚至做简单后端和小游戏,用途真的特别广。
最后分享几句实在又走心的话送给正在学Python的你:
1. 慢慢来别着急,代码不会辜负每一个愿意坚持敲键盘的人。
2. 现在多学一点技能,未来就多一份选择的底气。
3. 与其原地迷茫焦虑,不如从一行Python代码开始悄悄变强。
4. 看似不起眼的日复一日,终会在将来的某天,让你看到坚持的意义。
铁汁们~ 觉得内容有用的话,麻烦点个赞、关注一波,后续会持续更新Python入门、实战、自动化相关笔记,咱们一起慢慢进阶。
文章有哪里讲得不妥的,欢迎评论区随时指正,大家一起交流进步!
兄弟们,咱们一起学好Python,悄悄逆袭~~~
