python语言基础 - day12~14 模块包、文件操作、json数据、异常处理
1、模块
所用文件路径
1)什么是模块
python中的每一个py文件
都是一个模块,可以在一个模块中去使用另外模块的全局变量(变量、函数、类),但是需要提前导入该模块
2)如何导入模块
导入模块的方法总结起来有以下几种:
a.import 模块名
- 导入模块中没有被阻止导入的所有的全局变量:'模块名.'
b.import 模块名 as 别名
- 导入模块中的所有全局变量:'别名.'
c.from 模块名 import 变量名
- 导入模块中的指定变量:直接使用变量
d.from 模块名 import 变量名1 as 别名1, 变量名2, 变量名3...
- 导入模块中的指定变量:直接使用变量(变量别名)
d.from 模块名 import *
:导入模块中所有的全局变量
3)导入模块的原理
不管是通过import
导入,还是通过from-import
导入,在导入的时候,模块里的代码都会被执行(python的import
自带查重功能,如果模块被导入过就不会再被重复导入,即被导入的模块只会执行一次)
以下代码导入到两次test包中的test1模块,但是只执行了一次test1中的代码
# test.test1中内容
A = 100
def func1():
print('这个是test1模块的func1函数!')
func1()
# module中执行以下代码
import test.test1
import test.test1
# 运行结果
"""
这个是test1模块的func1函数!
Process finished with exit code 0
"""
# 导入test1模块两次,但是只执行了一次test1模块中的代码(其他导入方式也是一样的效果,可以自行试验)
4)阻止导入
定义模块时,通过if __name__ = "__main__"'
这个if语句来阻止在导入模块时不需要执行的代码被执行(在这个if语句中的代码在导入时不会被其他模块执行,不在if中的代码在导入时会被其他模块执行)
阻止导入原理:
每个py文件都有一个__name__
变量来保存当前模块的模块名,当直接执行某个模块时,这个文件的__name__
值为自动变成"__main__"
# test.test1中内容
A = 100
def func1():
print('这个是test1模块的func1函数!')
def func2():
print('这个是test1模块的func2函数!')
func1()
if __name__ == '__main__':
func2()
# module中执行以下代码
import test.test1
# 运行结果
"""
这个是test1模块的func1函数!
Process finished with exit code 0
"""
# 导入test1模块,只会执行调用func1的代码,不会执行地调用func2的代码,调用func2的代码被阻止导入了
2、包
1)什么是包
包就是一个含有__init__.py
文件的文件夹,用来保存模块,目的是为了方便在别的地方使用
上图中的test就是一个包含两个模块的包(其中__init__.py
文件是包必含的文件)
2)怎么样使用包中的模块
导入包的几种方式:
① import 包名.模块 - 包名.模块名.变量
② import 包名.模块名 as 新名 - 对’包名.模块名’重命名,通过’新名.变量’的方式使用变量
③ from 包名 import 模块名1, 模块名2, … - 模块名.变量
④ from 包名 import 模块名1 as 新模块名1, 模块名2, … - 新模块名1.变量
⑤ from 包名.模块名 import 变量名1, 变量名2, 变量名3, … - 直接使用变量
# A是test1中的一个全局变量
# 方法一
import test.test1 as test1
a = test1.A
print(a)
# 方法二
from test import test1 as t1
a = t1.A
print(a)
# 方法三
from test.test1 import A
a = A
print(a)
# 以上3种方法单独执行都输出以下内容
"""
这个是test1模块的func1函数!
100
"""
3)定制包的__init__.py
文件
__init__.py
文件的作用,不管是以哪种方式导入包,都会先执行这个文件中的代码。不可以通过包直接导入其他文件的变量,但是可以通过包直接导入__init__.py
文件中的变量。以下代码可以证明以上结论:
# test包的__init__.py文件中的代码
# 第一种
import test.test1
C = 300
# package模块中的代码
import test
# 报错:A不是test的模块,A是包的模块(test1)的变量
# print(test.A) # AttributeError: module 'test' has no attribute 'A'
print(test.C) # 300
# 输出以下内容
"""
这个是test1模块的func1函数!
300
"""
3、文件操作
1)数据持久化
数据默认存储在运行内存中,运行内存中数据存在的周期是从程序运行开始到程序运行结束,要想长久保存,就需要将数据保存到磁盘中,如果想要将数据保存到磁盘中,就需要先将数据保存到一个文件中,然后将该文件保存到磁盘中。
2)文件操作
一个完整的文件操作包括:打开 -> 读/写 -> 关闭
3)python实现文件操作
① 打开文件
使用open函数 - open(path, mode, ..., encoding=None)
path - 文件路径(绝对路径、相对路径)
绝对路径 - 文件在计算机中的全路径
相对路径 - 用.
来替代路径中的部分,只写部分.
- 表示当前目标(当前正在写代码的文件所在的目录),一个点可以省略..
- 表示当前目标的上层目录...
- 表示当前目标的上层目录的上层目录
# 绝对路径
path0 = r"E:\python\PyCharm\01、语言基础\day13 - 包文件操作和异常\04 文件操作.py" # 当前文件
path1 = r"E:\python\PyCharm\01、语言基础\day13 - 包和文件操作\files\message.txt"
pathx = r"E:\python\PyCharm\01、语言基础\day13 - 包文件操作和异常\test3\game.py"
# 相对路径
# . - 代表文件夹'day13 - 包和文件操作'
path2 = r'.\files\message.txt'
path3 = r'files\message.txt'
# .. - 代表文件夹'01、语言基础'
path4 = r'..\day13 - 包文件操作和异常\files\message.txt'
path5 = r'..\day13 - 包文件操作和异常\test3\game.py'
mode - 字符串,打开方式(决定打开文件后能执行哪种操作,决定读写数据的类型)'r'
- 只读操作,读取位置在文件的开头(打开一次文件,第一次读取位置在文件开头,从第二次读取开始,读取位置都做文件末尾)(默认)'w'
- 只写操作(使用’w’打开文件会清空文件)'a'
- 只写操作 (使用’a’打开文件不会清空文件,读取位置在文件结尾)
't'
- 表示文本数据,对应 str 类型(默认)
'b'
- 表示二进制数字,对应bytes类型
'rt'/'tr'/'t'
- 都表示读取文本数据
'wt'/'tw'/'w'
- 都表示写入文本数据
'at'/'ta'/'t'
- 都表示写入文本数据
'rb'/'br'/'b'
- 都表示读取二进制数据
'wb'/'bw'
- 都表示写入二进制数据
'ab'/'ba'/
- 都表示写入二进制数据
注意:
1、如果一个文件不存在,以只读方式打开会报错(FileNotFoundError),以只写方式打开不会报错,并且会自动创建该文件2、如果是文本文件,打开的时候可以带’t’,也可以带’b’,如果是非文本文件,打开的时候只能带’b’
encoding - 设置文本文件的编码格式,一般使用’utf-8’
**注意:**1)打开同一个文件,读和写的方式要一致;
2)打开的时候如果带’b’,不能设置encoding
② 文件的读/写操作
读取文件:文件对象.read()
读一行:文件对象.readline()
- 这种用法一般很少用(每次读一行,读了一次后读写位置会移动到末尾,要读其他行,需要用seek函数(readline只能读文本文件))
移动光标位置:文件对象.seek(0)
- 将光标(读写位置)移动到文件开头,一般参数都用0,如果用其他的,因为编码方式的元素可能会出错(只能在读取文件时使用seek函数)
写入文件:文件对象.write()
# text.txt/test.txt不存在
# f = open('./files/text.txt', 'r') # 'r'方式打开不存在的文件报错 FileNotFoundError
f = open('./files/text.txt', 'wt') # 'w'方式打开不存在的文件不会报错,并且会创建text.txt文件
f = open('./files/test.txt', 'at') # 'a'方式打开不存在的文件不会报错,并且会创建test.txt文件
f = open(path1, 'ra')
re1 = f.read()
f.close()
f = open(path1, 'wb')
f.write('这是在写入')
f.close()
# 写入二进制数据
f = open(path1, 'ab')
③关闭 - 文件对象.close()
**注意:**文件关闭后不能再进行读写操作,每次使用文件后要记着关闭文件
f = open(path1)
f.read()
f.close()
# f.read() # ValueError: I/O operation on closed file.
**不需要手动关闭已打开文件的操作方式:**在with里面的文件操作结束后,系统会自动关闭文件
"""
with open(参数列表) as 文件名:
文件操作
"""
with open('files/text1.txt', 'w') as f:
f.write('用with方式打开文件并写入文字信息,操作结束后文件会自动关闭')
with open('files/text1.txt') as f:
re = f.read()
print(re) # 用with方式打开文件并写入文字信息,操作结束后文件会自动关闭
4)with语法
使用with语法读写文件,不需要程序员手动关闭文件,with结束后系统会自动关闭文件
"""
with open(path, mode, encoding, ...) as f:
文件读写操作
"""
with open('files/data1.txt', encoding='utf-8') as f:
re1 = f.read()
with open('files/data1.txt', 'w', encoding='utf-8') as f:
re2 = f.write('今天是星期几?\n'+re1)
print(re1, re2, sep='\n')
4、数据的持久化
怎么样做到数据持久化
1)创建一个文件来保存需要持久化的数据
2)需要这个数据的时候从文件中获取这个数据
3)如果在程序中对数据进行了修改,需要将最新的数据更新到文件中
# 练习2:添加学生
# a.每运行一次程序添加一个学生,并且打印已经添加过的所有的学生
# b.每运行一次程序添加一个学生,并且以列表的形式打印已经添加过的所有的学生
# stu1 -> stu1 ['stu1']
# stu2 -> stu1 stu2 ['stu1', 'stu2']
# 小明 -> stu1 stu2 小明 ['stu1', 'stu2', '小明']
# 直接打印已经添加过的所有的学生
name = input('请输入学生姓名:')
f = open('students1.txt')
re1 = f.read()
print(re1+name)
f = open('students1.txt', 'a')
f.write(name+' ')
f.close
# 列表形式打印(先在students2表里面给一个初始值'[]')
name = input('请输入学生姓名:')
f = open('students2.txt')
re1 = eval(f.read())
re1.append(name)
print(re1)
f = open('students2.txt', 'w')
f.write(str(re1))
f.close
5、json数据
1)什么是json
json是一种几乎所有高级语言都支持处理的通用数据格式,所以json一般用于多种语言间的数据交流(比如服务器和客户端之间的交流)
2)json的数据格式
json文件:json文件是保存 满足 json 格式要求的数据 的文件
json文件的格式要求:1、有且只有一个数据
2、这个数据必须是满足 json 支持的数据类型的数据
json支持的数据类型:
"""
① 数字(Number) - 所有数字对应的数据类型,包括整数、浮点数、科学计数法表示的数(不支持复数
② 字符串(String) - 用`""`引起来的字符集,例如:"abc","s\nb","sd\u4e00",...
③ 布尔(Bool) - 只有true和false两个值
④ 数组(Array) - 相当于python的列表
⑤ 字典(Dictionary)- 相当于python的字典(key只能是字符串)
⑥ 空值 - null,多有python中的None
"""
json和python数据之间的转换是通过json模块中的函数
3)怎么将json数据转换成python数据
json.loads(json字符串)
:把json格式的字符串转换成python格式的数据
"""
json -> python
数字 int、float
字符串 字符串(将`""`变成`''`)
布尔 True/False(将首字母变为大写)
数组 列表(元素自动转换)
字典 字典(元素自动转换)
空值 None
"""
4)怎样将python数据转换成json数据
json.dumps(json字符串)
:把指定的python格式的数据转换成json格式的字符串
"""
python -> json
int 数字
float 数字
字符串 字符串(将`''`变成`""`)
布尔 true/false(将首字母变为小写)
列表/元组 数组(元素自动转换)
字典 字典(元素自动转换,key会转换成字符串)
空值 null
"""
python集合不能直接转换成 json 格式的数据
import json # 导入数据转换的模块
json1 = '[10, 1.234, "abc", true, {"1": "abc"}, ["a", 12, 3.45]]'
list1 = json.loads(json1)
print('python数据', list1) # python数据 [10, 1.234, 'abc', True, {'1': 'abc'}, ['a', 12, 3.45]]
list2 = [10, 1.234, 'abc', True, {1: 'abc'}, ['a', 12, 3.45]]
json2 = json.dumps(list2)
print('json数据', json2) # json数据 [10, 1.234, "abc", true, {"1": "abc"}, ["a", 12, 3.45]]
6、异常处理
1)什么是异常
异常就是错误,程序报错就是程序程序异常
2)捕获异常
异常捕获就是程序出错时不崩溃继续执行。
注意:不是所有的异常都可以捕获,只有在明知道会产生异常,但是又不能或者不方便修改代码来避免异常,这个时候就可以对异常进行捕获(比如:某个地方代码没有问题,但是用户输入参数的不符合要求,会导致程序出错,双方的行为都是合理的,但是这个时候程序会崩溃)
3)怎么捕获异常
捕获异常的语法:
"""
语法一:
try:
需要捕获异常的代码段 - 代码段1
except 异常类型1:
捕获到指定异常后会执行的代码段
...
finally:
代码块
其他代码
语法二:
try:
需要捕获异常的代码段 - 代码段1
except (异常类型1, 异常类型2, 异常类型3, ...):
捕获到指定异常后会执行的代码段
...
finally:
代码块
其他代码
语法三:
try:
需要捕获异常的代码段 - 代码段1
except 异常类型1:
捕获到指定异常后会执行的代码段2
except 异常类型2:
捕获到指定异常后会执行的代码段3
except 异常类型3:
捕获到指定异常后会执行的代码段4
...
finally:
代码块
其他代码
其中finally中的代码块,不管前面运行的结果怎么样,finally里面的代码都会执行
(没有异常、有异常没有被捕获、有异常被捕获)
执行过程:先执行try后面的代码段,在执行过程中如果出现异常,首先程序不崩溃,马上检查是哪种异常类型,如果异常类型是指定的异常类型,就直接执行对应的except后面的代码段,执行完except后面的代码段再执行finally后面的代码段,最后再执行其他代码。如果执行try里面的代码没有出现异常,except后面的代码不会执行,直接执行finally后面的代码段,然后再执行其他代码。
"""
try:
age = int(input('请输入年龄:'))
print({'a': 1}['b'])
print([2, 4, 6][100])
except ValueError:
print('输入的年龄格式不正确,只能输入数字!')
except IndexError:
print('索引错误,下标越界!')
finally:
print('finally里面的代码段')
# 执行结果
"""
请输入年龄:a
输入的年龄格式不正确,只能输入数字!
finally里面的代码段
请输入年龄:12
finally里面的代码段
Traceback (most recent call last):
File "E:/python/PyCharm/01、语言基础/day14 - json和异常/test1.py", line 4, in <module>
print({'a': 1}['b'])
KeyError: 'b'
"""
4)抛出异常
作用:主动让程序崩溃
语法:raise 异常类型
- 异常类型可以是系统异常类型,也可以是自定义的异常类型
注意:异常类型必须是Exception的子类
class AgeArror(Exception):
def __str__(self):
return '年龄值的范围是:0~150'
def func2(age: int):
if age < 0 or age > 150:
raise AgeArror
if age >= 18:
print('成年人')
else:
print('未成年人')