模块与包、json模块

【一】模块与包介绍

【1】什么是模块

  • 在Python中,一个py文件就是一个模块,文件名为 xxx.py,模块名则是xxx,导入模块可以引入模块中已经写好的功能。
    • 如果把开发程序比喻成制造一台电脑
    • 编写模块就像是在制造电脑的零部件
    • 准备好零件后,剩下的工作就是按照逻辑把它们组装到一起。
  • 将程序模块化会使得程序的组织结构清晰,维护起来更加方便。
  • 模块保证了代码的重用性,又增强了程序的结构性和可维护性。

【2】模块的优点

  • 极大地提高了程序员地开发效率
  • 增强了程序地健壮性和可读性

【3】模块的来源

  • 内置的:python解释器自带地,直接拿来使用的
  • 第三方的:别人写的,如果想使用,就要先下载再使用
  • 自定义的:自己写的

【4】模块的存在形式

  • 单模块
    • 就是自己定义的功能所在的py文件
    • 将自己定义的功能所在的py文件,总结起来,放到一个文件夹下构成了一个包
  • 必须有 __ init __.py 文件

【二】模块的使用

【0】准备

  • 新建一个文件foo.py
x = 1

# 定义一个普通函数
def get():
    print(x)


# 定义一个修改全局变量的函数
def change():
    global x
    x = 0

# 定义一个类,类里面有方法
class Foo:
    def func(self):
        print('the func from the foo')

【1】直接导入

  • import 语句
import py文件名/模块名

(1)Import 导入模块会发生哪些事

  • 要想在另外一个py文件中引用foo.py中的功能
  • 需要使用 import foo
import foo  	# 导入模块foo
a = foo.x  		# 引用模块foo中变量x的值赋值给当前名称空间中的名字a
foo.get()  		# 调用模块foo的get函数
foo.change()    # 调用模块foo中的change函数
obj = foo.Foo() # 使用模块foo的类Foo来实例化,进一步可以执行obj.func()
  • 加上 foo. 作为前缀就相当于指名道姓地说明要引用foo名称空间中的名字
  • 执行 foo.get()foo.change() 操作的都是源文件中的全局变量 x
  • 需要强调一点是,第一次导入模块已经将其加载到内存空间了,之后的重复导入会直接引用内存中已存在的模块,不会重复执行文件
    • 通过 import sys
    • 打印 sys.modules的值可以看到内存中已经加载的模块名

(2)import导入模块方式

  • 用import 语句导入多个模块
    • 可以写多行 import 语句
import module1
import module2
    ...
import moduleN
  • 还可以在一行导入,用逗号分隔开不同的模块
import module1,module2,...,moduleN
  • 但其实第一种形式更为规范,可读性更强,推荐使用

(3)详细导入语法

# from 模块名 import 属性名

(4)导入所有参数和方法

  • 想要导入模块中所有参数和方法
# 把foo中所有的名字都导入到当前执行文件的名称空间中,在当前位置直接可以使用这些名字
from foo import *  

a = x
get()
change()
obj = Foo()
  • *的方式会带来一种副作用
    • 即我们无法搞清楚究竟从源文件中导入了哪些名字到当前位置
    • 这极有可能与当前位置的名字产生冲突。
  • 模块的编写者可以在自己的文件中定义__all__变量用来控制 * 代表的意思
# foo.py

# 该列表中所有的元素必须是字符串类型,每个元素对应foo.py中的一个名字
__all__=['x','get'] 
x=1
def get():
    print(x)
def change():
    global x
    x=0
class Foo:
    def func(self):
       print('from the func')
  • 这样我们在另外一个文件中使用* 导入时,就只能导入__all__定义的名字了
# 此时的*只代表x和get

from foo import * 

x 			#可用
get()   	#可用
change() 	#不可用
Foo() 		#不可用

(5)重命名模块

  • from ... import ... as ... 语句
from 模块位置 import 模块名 as 自定义名字
  • 可以在当前位置为导入的模块起一个别名
#为导入的模块foo在当前位置起别名f,以后再使用时就用这个别名f
import foo as f 
f.x
f.get()

【三】循环导入问题

  • 在一个文件中导入调用了另一个文件
  • 另一个文件在调用当前文件

【1】问题来源

  • m1.py
print('正在导入m1')
from m2 import y

x='m1'
  • m2.py
print('正在导入m2')
from m1 import x

y='m2'
  • run.py
import m1

【2】解决方法

(1)方法一

  • 导入语句放到最后,保证在导入时,所有名字都已经加载过
  • m1.py
print('正在导入m1')
x='m1'
from m2 import y
  • m2.py
print('正在导入m2')
y='m2'
from m1 import x
  • run.py
import m1
print(m1.x)
print(m1.y)

(2)方法二

  • 导入语句放到函数中,只有在调用函数时才会执行其内部代码
  • m1.py
print('正在导入m1')

def f1():
    from m2 import y
    print(x,y)

x = 'm1'
  • m2.py
print('正在导入m2')

def f2():
    from m1 import x
    print(x,y)

y = 'm2'
  • run.py
import m1

m1.f1()

【四】模块加载和搜索顺序

【1】模块的分类

  • 模块分为四个通用类别,分别是:
    • 1、使用纯Python代码编写的py文件
    • 2、包含一系列模块的包
    • 3、使用C编写并链接到Python解释器中的内置模块
    • 4、使用C或C++编译的扩展模块

【2】加载顺序

  • 先c 和 c++ 扩展出去的模块
  • 使用c语言编写的底层代码
  • 内置的一系列模块 (python解释器自带的和你安装 pip install )
  • 纯python编写的自己定义的模块

【3】查找顺序

# 先从自己的局部查
'''
def func():
    import time
'''
# 再从全局查
'''
import time 
'''
# 去内建查
'''
python解释器自带的模块和你安装的模块中查,查出对应的模块再使用
'''
# 去底层 c 语言查
'''
有些功能ctrl进去看源码发现只要一个 pass
使用c语言写的,但是不想让你看到所有就省略掉了
'''

【五】绝对路径和相对路径

【1】相对路径

# D:\Python\PythonProjects\PythonProjects29\day17
# ./ 表示当前同级目录下
# ../ 表示当前目录的上一级目录
# 默认就是当前目录下
with open('../user_data.text', 'w', encoding='utf-8') as fp:
    fp.write('111')

【2】绝对路径

# 在python内部查找的顺序都是绝对路径
import sys
print(sys.path)
# [
# 'D:\\Python\\PythonProjects\\PythonProjects29\\day17',
# 'D:\\Python\\PythonProjects\\PythonProjects29\\day17',
# 'D:\\PyCharm\\plugins\\python\\helpers\\pycharm_display',
# 'D:\\Python38\\python38.zip',
# 'D:\\Python38\\DLLs',  # 这里放的就是c语言源码编译后的扩展包
# 'D:\\Python38\\lib', # 放的是内置的模块或者安装的模块
# 'D:\\Python38', # 安装python解释器的路径
# 'D:\\Python38\\lib\\site-packages', # 这里面也有部分安装的的包 ,默认安装到 site-packages
# 'D:\\PyCharm\\plugins\\python\\helpers\\pycharm_matplotlib_backend'# 回到pycharm
# ]

【六】包

【1】什么是包

  • 包是一个模块的集合,它可以将多个模块的功能组合到一起。
  • 包可以按照其功能和作用进行分类,方便用户查找和使用。
  • 包是在Python标准库中定义的一种特殊类型的模块,可以通过import语句来引入和使用。
  • Python的包分为标准库包和第三方库包。
    • 标准库包是Python内置的包,包含了一些基本的模块和函数,如os、sys、random等;
    • 第三方库包是第三方开发的包,通常提供了更加丰富和高级的功能。

【2】如何创建包

# 【1】创建一个文件夹
# 在文件夹内部创建 一个 __init__.py 文件
# 这个文件夹就叫包

# 【2】在pycharm右键文件新建 package
# 自动创建 __init__.py 文件

【3】使用包

(1)创建包

  • 创建一个 cal 的包,包中有一个计算器的 model ,结构如下:
  • __ init __.py作用就是再导入当前 包的时候进行初始化操作 ---> 先检索 init文件
|-cal
	|-__init__.py
	|-calculator.py
  • calculator.py
def add(a, b):
    return a + b


def reduce(a, b):
    return a - b


def multiply(a, b):
    return a * b


def divide(a, b):
    return a / b

(2)直接使用包

  • Python 包的使用和模块的使用类似,下面是导入的语法:
import 包名.包名.模块名
  • 我们在 use_cal.py 中导入 calculator.py
# 导入包
import cal.calculator
# 使用包的模块的方法
print(cal.calculator.add(1,2))

(3)详细使用包

  • 导入调用的时候报名比较长,这样就可以使用from ... import ...语句来简化一下。
from 包名.模块名 import 模块中的方法
  • use_cal.py 中导入 calculator.py
# 导入包
from cal import calculator

# 使用包的模块的方法
print(calculator.multiply(3, 6))

【4】制作包

  • 在包下的__init__.py中注册相关变量
# 注意这里要用相对路径
# 从 calculator.py 中将需要导出的方法导入到这里
from .calculator import add, reduce
  • 使用包
    • use_cal.py
# 将注册在 __init__.py 中的方法导入过来
from cal import add, reduce

# 使用包的模块的方法
print(add(3, 6))

【七】导入语法总结

# import 模块名 语法 只会检索当前模块内的所有变量名
# import 包名 语法 会先自动检索 __init__.py 文件内的所有变量名 然后再去检索 每个模块里面的变量名

# 加载的时候多加载了一层  __init__.py
# 查找的时候也多查找了一层  __init__.py

# 不管是在模块还是包还是自己的文件中
# 只要检索到指定名字就会停止检索

【八】json模块

【1】什么是序列化

# 将Python中的字典、列表、元组 ... 转换成 字符串类型
# 如果使用str强制转换数据类型,造成的后果就是转换后的字符串无法转回Python对象

【2】什么是反序列化

# 将字符串类型的数据转换成Python对象(列表、字典、元组 ... )
# 能将python对象转为字符串 --> 字符串转回python对象

【3】json模块

(1)导入json模块

import json

(2)保存和读取

# (1)序列化保存Python对象数据
user_data_dict = {
    'username': "chosen",
    "password": "521"
}
# 保存到本地的文件中 保存进去是字典格式的字符串 独取出来也是字典格式的字典
'''
with open("user_data.text", 'w', encoding='utf-8') as fp:
    fp.write(str(user_data_dict))

with open("user_data.text", 'r', encoding='utf-8') as fp:
    data = fp.read()
print(data)
print(dict(data))
'''
# 存储为json文件数据
with open('user_data.json', 'w', encoding="utf-8") as fp:
    json.dump(obj=user_data_dict, fp=fp)
    
# 在内部自动将单引号全部转换为双引号,然后保存进去

# (2)将json格式数据转换W为Python对象
with open('user_data.json', 'r', encoding="utf-8") as fp:
    data = json.load(fp=fp)
print(data, type(data))

(3)转换

# 反序列化和序列化方法之转换
# 将一个字典转换为字符串  再转回字典

# (1)将字典转换为字符串格式
data_json_str = json.dumps(obj=user_data_dict)
print(data_json_str, type(data_json_str))  # {"username": "chosen", "password": "521"} <class 'str'>


# (2)将字符串转回 python对象
data_json_dict = json.loads(data_json_str)
print(data_json_dict, type(data_json_dict))  # {'username': 'chosen', 'password': '521'} <class 'dict'>

(4)保存中文数据

user_data = {'name': "蚩梦", "age": 18}
with open('data.json', 'w', encoding='utf-8') as fp:
    json.dump(obj=user_data, fp=fp, ensure_ascii=False)

# 编码和解码
# 编码 encode(编码格式)
# 解码 decode(编码格式)

posted @ 2024-04-23 14:51  光头大炮  阅读(5)  评论(0编辑  收藏  举报