python语言基础 - day12~14 模块包、文件操作、json数据、异常处理

1、模块

所用文件路径

网络数据包解析 python python数据包处理模块_json

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文件的文件夹,用来保存模块,目的是为了方便在别的地方使用

网络数据包解析 python python数据包处理模块_数据_02

上图中的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('未成年人')