Python3.11教程3:模块和包(pip/conda)、文件系统(os/ shutil/json/pickle/openpyxl/xlrd)
文章目录
- 七、模块和包
- 7.1 模块
- 7.1.1 模块搜索路径
- 7.1.2 `PYTHONPATH`和`sys.path`
- 7.1.2 模块的导入和常见错误
- 7.1.3 模块的缓存机制
- 7.1.4 `__name__` 和 `__main__` 函数
- 7.2 标准库
- 7.3 包
- 7.3.1 创建包
- 7.3.2 导入包
- 7.3.3 pip包管理器
- 7.3.4 conda
- 7.4 如何组织和管理大型项目中的模块与包
- 7.4.1 最佳实践
- 7.4.2 Sphinx
- 八、 I/O系统(文件管理)
- 8.1 `I/O`简介
- 8.2 读写文本、二进制文件
- 8.2.1 open函数
- 8.2.2 文件指针和文件截断(seek&truncate)
- 8.2.3 读写函数(read、write)
- 8.2.4 上下文管理器(with)
- 8.3 读写excel/csv文件
- 8.3.1 pandas读写excel/csv文件
- 8.3.2 openpyxl库
- 8.3.3 xlrd库(打开加密excel)
- 8.4 os模块
- 8.4.1 os模块常用函数
- 8.4.2 os.walk函数
- 8.5 shutil 模块(移动、复制、压缩文件)
- 8.6 Python数据的序列化
- 8.6.1 数据的序列化和反序列化
- 8.6.2 json模块
- 8.6.3 pickle模块
- 8.6.4 示例:使用pickle保存lightGBM模型&加载预测
本文相关链接:
- Python官网、Python 3.11.5 中文文档、慕课:Python语言程序设计、Real Python :Write More Pythonic Code
- Miniconda、Anaconda、conda文档
- Python 标准库官方文档、 《os — 多种操作系统接口》、《os.path — 常用路径操作》、《shutil — 高阶文件操作》
- Pandas文档《Input/output》、 openpyxl官方文档、xlrd官方文档、json模块、pickle模块
七、模块和包
在Python中,模块(Moudle)和包(Package)是组织和管理代码的重要方式。它们有助于将代码分割成可管理的块,提高了代码的可重用性和可维护性。现在,让我们深入了解这两个概念。
7.1 模块
模块是一个包含Python代码的文件,其文件名是模块名加后缀名 .py
。文件中可以包含函数、变量和类,它们被组织在一起以便在其它地方重用。所以我们只需编写Python代码并将其保存为.py文件,就创建了一个模块,其他程序就可以导入它并使用其中的功能。
模块的文件名应该是一个有效的Python标识符,遵循Python的命名约定,不能与Python的关键字或者与标准库、已安装的第三方库重名,防止冲突。最好使用有描述性的变量、函数和类名,以提高代码的可读性。
7.1.1 模块搜索路径
在Python中,要使用模块或包中的内容,您需要导入它们。Python解释器在导入模块时会搜索模块的路径,包括以下位置:
- 当前目录
- Python标准库的安装位置
- 环境变量
PYTHONPATH
中指定的目录 - Python内置的一些默认目录
这些路径按照优先级的顺序搜索。首先,解释器会查找当前目录是否有所需的模块,然后才会继续搜索其他路径。如果找到匹配的模块,解释器会导入它。
标准库通常安装在Python的安装目录中,而site-packages目录包含了第三方模块的安装位置。运行以下代码,你将看到Python标准库的安装位置和site-packages目录的路径。
import sys
import siteprint("Python标准库的安装位置:")
print(sys.prefix)print("\nPython的site-packages目录:")
print(site.getsitepackages())
7.1.2 PYTHONPATH
和sys.path
PYTHONPATH
环境变量PYTHONPATH
允许您自定义模块搜索路径,这对于在项目中使用自定义模块或第三方模块非常有用。你可以使用下面的方式查看和设置PYTHONPATH
。
-
在Linux或macOS系统上,可以在终端中执行
echo $PYTHONPATH
命令来查看PYTHONPATH,使用export PYTHONPATH=/path/to/your/custom/modules
以在PYTHONPATH中指定自定义模块的搜索路径。 -
在windows系统中,可以使用Python代码来访问和配置PYTHONPATH
import ospythonpath = os.environ.get('PYTHONPATH') if pythonpath:print("PYTHONPATH的值:", pythonpath) else:print("PYTHONPATH未设置") # 未设置PYTHONPATH时,其值为None
import os# 设置PYTHONPATH的值 new_pythonpath = "/path/to/your/custom/modules" os.environ['PYTHONPATH'] = new_pythonpath# 验证是否已成功设置 pythonpath = os.environ.get('PYTHONPATH') if pythonpath:print("已设置的PYTHONPATH的值:", pythonpath) else:print("PYTHONPATH未设置")
上述代码仅在当前Python进程中更改了PYTHONPATH的值。如果您希望永久更改系统环境变量,需要在系统环境变量中添加。
sys.path
sys.path
是一个包含目录路径的列表,Python解释器在导入模块时会搜索这些路径。以下是如何使用sys.path
管理模块搜索路径的示例:
import sys# 查看当前sys.path的值
print("当前sys.path:", sys.path)# 添加一个自定义模块路径到sys.path
custom_module_path = "/path/to/your/custom/modules"
sys.path.append(custom_module_path)# 再次查看sys.path,您将看到新路径已添加
print("更新后的sys.path:", sys.path)# 现在可以导入自定义模块
import custom_module
sys.path
和PYTHONPATH
的区别
sys.path
和 PYTHONPATH
都用于管理 Python 模块的搜索路径,但它们之间存在一些重要的区别:
-
作用范围:
-
sys.path
是 Python 解释器级别的,它仅影响当前 Python 进程中的模块搜索路径。这意味着对sys.path
的更改仅在当前 Python 程序中生效,不会影响全局环境或其他 Python 进程。 -
PYTHONPATH
是操作系统级别的环境变量,它影响所有 Python 进程的模块搜索路径,包括您在命令行中运行的 Python 脚本、Python IDE 中的代码,以及其他所有 Python 程序。因此,更改PYTHONPATH
可以全局影响 Python 模块的搜索路径。
-
-
优先级:
-
当导入模块时,
sys.path
中的路径优先于PYTHONPATH
中的路径。这意味着如果在sys.path
中找到了匹配的模块,将首先使用它,而不会查找PYTHONPATH
中的路径。 -
如果没有在
sys.path
中找到模块,Python 解释器将继续查找PYTHONPATH
中的路径。 -
如果使用了虚拟环境,虚拟环境会自动管理
sys.path
,以便在虚拟环境中安装的模块优先于全局模块。这可以确保项目的依赖关系得到良好的隔离和管理。
-
-
动态性:
-
您可以在运行时使用 Python 代码修改
sys.path
,以动态添加或删除模块搜索路径,而不需要重新启动 Python 进程。 -
要更改
PYTHONPATH
,您通常需要重新启动与环境变量关联的 Python 进程,这意味着更改可能需要在启动新进程之前生效。
-
-
局部性:
-
sys.path
更适合项目级别的管理,您可以在项目代码中使用它来管理模块搜索路径,以确保项目的依赖关系得到良好的隔离。 -
PYTHONPATH
更适合全局配置,用于设置系统范围的模块搜索路径,可能影响多个项目和 Python 进程。
-
综上所述,sys.path
更加灵活,适用于在项目级别管理模块搜索路径,不会影响全局环境。而 PYTHONPATH
用于全局配置,影响所有 Python 进程。通常情况下,在项目中使用虚拟环境和 sys.path
更为常见,因为它提供了更好的隔离性和控制,这对于在不同项目中使用不同的模块版本或自定义模块非常有用。
7.1.2 模块的导入和常见错误
Python提供了不同的模块导入方式,以满足不同的需求。
- 使用
import module_name
导入整个模块。 - 使用
from module_name import function_name
导入模块中的特定函数或变量。 - 使用
as
关键字为模块或导入的内容创建别名。
示例:
import math # 导入整个math模块
result = math.sqrt(25) # 使用模块中的函数from math import sqrt # 导入math模块中的sqrt函数
result = sqrt(25) # 可以直接使用函数,不需要模块前缀import numpy as np # 导入NumPy库并为其创建一个别名my_array = np.array([1, 2, 3]) # 创建一个NumPy数组
除了使用完整的绝对路径或模块名,也可以使用相对路径来导入模块,这分两种情况:
- 相对于当前模块的相对路径导入: 这种方式允许您在同一目录中的模块之间进行相对路径导入。
假设你有以下项目结构:
my_project/├── main.py├── module1.py└── module2.py
如果你想从 module1.py
中导入 module2.py
,您可以使用相对路径导入如下:
# module1.pyfrom . import module2 # 使用相对路径导入
我们一般用
.
表示当前目录,使用..
表示父目录。
- 相对于顶级包的相对路径导入
如果您的项目是一个包(包含一个__init__.py
文件的目录),您可以使用相对于顶级包的相对路径导入。
假设您有以下项目结构:
my_package/├── __init__.py├── subpackage/│ ├── __init__.py│ ├── module1.py│ └── module2.py└── main.py
如果您想从 module1.py
中导入 module2.py
,可以使用相对路径导入如下:
# module1.pyfrom ..subpackage import module2 # 使用相对路径导入
在这个示例中,..
表示父包(my_package
),然后导入了子包 subpackage
中的 module2.py
。
需要注意的是,相对路径导入通常在包内部使用,以便在包内的模块之间进行导入,这可以使项目结构更清晰,但需要谨慎使用,以确保相对路径的正确性。通常更常见的是使用绝对路径导入或直接使用模块名导入。
7.1.3 模块的缓存机制
此部分更多细节及决策流程图,详见 PEP 3147
为了快速加载模块,Python解释器会缓存已经导入的模块,避免重复导入和提高性能。这意味着模块只会在第一次导入时执行一次,后续导入将使用缓存的版本。
Python 一般把模块的编译版本缓存在 __pycache__
目录中,文件名为 module.version.pyc,其中海报好了编译器的版本号,例如CPython 的 3.3 发行版中,spam.py
的编译版本缓存为 __pycache__/spam.cpython-33.pyc
。这种命名惯例让不同 Python 版本编译的模块可以共存。
另外,Python 会对比编译版与源码的修改日期,查看编译版是否已过期,是否要重新编译,此进程是完全自动的,与平台也没有关系,因此,Python可在不同架构的系统之间共享相同的库。
7.1.4 __name__
和 __main__
函数
__name__
是一个内置的特殊变量,当模块被导入时,__name__
的值是模块的名称。但当模块被直接运行时,__name__
的值是 "__main__"
,所以它可用于确定模块是以主程序运行还是被导入到其他程序中。
我们在__main__
函数中编写的代码,只有在模块被直接运行时才执行,而在被导入时不执行。假设我们有一个名为 my_module.py
的模块,其中包含以下代码:
# my_module.pydef my_function():print("Function called.")if __name__ == "__main__":print("This module is run directly as the main program.")
else:print("This module is imported.")
现在,如果我们在另一个脚本中导入这个模块,只会执行 else
分支,因为此时__name__
的值是模块的名称:
import my_module # 输出 "This module is imported."
但如果我们直接运行这个模块, if __name__ == "__main__":
,会执行其下的代码块:
python my_module.py # 输出 "This module is run directly as the main program."
这使得我们可以在模块中包含一些用于测试或执行的代码,而不必担心它们会在导入时执行。
7.2 标准库
详见Python 标准库官方文档
库是一组相关的模块的集合,通常具有特定的领域或功能。库也可以称为包。标准库(Standard Library)是Python内置的一组模块和功能,Python生态系统的核心部分。这些模块和功能提供了各种常见任务和操作的标准解决方案。Windows 版本的 Python 安装程序通常包含整个标准库,往往还包含许多额外组件。详情请参考官方文档。
7.3 包
包是一个包含多个模块的目录。它允许将相关的模块组织在一起,形成一个层次结构。包有助于更好地组织大型项目的代码。它们还可以避免命名冲突,因为每个包内的模块都有自己的命名空间。
7.3.1 创建包
创建包只需创建一个包含__init__.py
文件的目录,并在其中放置模块文件。这个__init__.py
文件可以为空,但它表明这是一个包。下面详细介绍一下 __init__.py
文件的作用。
-
标识一个目录作为包
如果你希望将一个目录视为Python的包(package),那么这个目录中必须包含一个名为
__init__.py
的文件,Python会根据这个文件来判断这个目录是否应该被当作一个包来处理。 -
防止出现目录名称与模块名称冲突的情况。
例如,如果没有
__init__.py
文件,Python可能会将一个名为string
的目录误认为是一个包,从而导致后续搜索模块时出现问题。 -
初始化包的某些功能
__init__.py
也可以包含Python代码,这可以是在导入包时自动执行的初始化代码,或者定义包的公共接口。例如,你可以设置特殊变量__all__
,它主要用于控制模块的公共接口,指定在使用from package import *
语句时,一个模块或包中哪些属性、函数、类等应该被导入到其他模块中。以下是关于__all__
的详细介绍:
-
作用:
__all__
的作用是限制通过from module import *
语句导入的内容,以避免导入不需要的标识符,同时允许开发者明确指定哪些标识符应该是模块的公共接口。
-
使用方式:
-
__all__
是一个包含字符串的列表(List),其中的每个字符串都是模块内部定义的标识符的名称。 -
在一个模块的顶层,你可以定义
__all__
变量, 这将明确指定了在from module import *
语句中可以被导入的标识符。假设有一个模块my_module.py
包含以下内容:def public_function():passdef _private_function():passclass PublicClass:passclass _PrivateClass:pass__all__ = ['public_function', 'PublicClass']
-
如果使用
from my_module import *
语句,只有public_function
和PublicClass
会被导入,而_private_function
和_PrivateClass
不会被导入。 -
如果使用
from my_module import _private_function
,则可以导入_private_function
,因为它在__all__
中没有被列出。
-
-
注意事项:
-
__all__
不是Python的强制性规定,而是一种约定。它主要用于指导其他开发者使用模块时应该导入哪些内容。 -
单下划线
_
开头的标识符通常被认为是私有的,不应该被直接导入,但仍然可以在需要的情况下导入。
-
总之,__all__
是一种用于控制模块或包公共接口的方式,它有助于提高代码的可维护性和可读性,同时避免导入不必要的标识符。
7.3.2 导入包
我们同样使用import语句,并指定包名和模块名来导入包中的模块。包可以形成层次结构,即包含子包和子包下的模块,只需指定完整的路径,也可以完成导入。一个常见的项目结构可能如下所示:
my_project/├── __init__.py├── module1.py├── module2.py└── subpackage/├── __init__.py├── submodule1.py└── submodule2.py
# module1.pyfrom ..subpackage import module2 # 使用相对路径导入
在实际使用中,尽量避免使用 from module import *
,最好是明确导入需要的标识符,例如 from module import func1, class1
,因为这会产生两个问题:
-
污染命名空间(Namespace Pollution):
- 当你使用
from module import *
时,Python会将该模块中的所有标识符都导入到当前的命名空间中,包括模块中可能没有被明确设计为公共接口的标识符。这意味着你的命名空间会变得非常拥挤,充斥着许多你可能并不需要的标识符,即命名空间污染。 - 这些额外的标识符可能会与你的代码中已经定义的标识符产生冲突,导致不可预测的行为或错误。
- 当你使用
-
代码难以理解:
- 当你在代码中看到大量的
from module import *
语句时,很难确定哪些标识符实际上是来自于这个模块,因为它们并没有明确地被列出。这会使代码变得难以理解和维护,因为你无法快速识别哪些标识符来自哪个模块。 - 同时,如果你使用了多个 from module import * 语句,不同模块中的标识符可能会相互覆盖,进一步增加了混乱和错误的可能性。
- 当你在代码中看到大量的
7.3.3 pip包管理器
pip是Python包管理器,专用于安装、升级和管理Python包。以下是常用的pip命令:
pip命令 | 描述 |
---|---|
pip --version | 验证pip是否安装并显示版本号 |
pip list | 列出已安装的所有包及其版本号 |
pip install --upgrade pip | 升级pip到最新版本 |
pip install package_name | 安装包 |
pip install package_name==desired_version | 安装特定版本的包 |
pip install --upgrade package_name | 升级指定包 |
pip uninstall package_name | 卸载指定包 |
pip freeze > requirements.txt | 将当前环境的包列表保存到requirements.txt文件中 |
pip install -r requirements.txt | 从requirements文件安装所有依赖项 |
pip show package_name | 显示指定包的详细信息,包括版本和安装路径 |
虚拟环境相关命令 | 描述 |
---|---|
pip install virtualenv | 安装虚拟环境模块(如果需要的话) |
python -m venv myenv | 创建新的虚拟环境(myenv是虚拟环境的名称) |
myenv\Scripts\activate (Windows) | 激活虚拟环境(Windows上) |
source myenv/bin/activate (macOS和Linux) | 激活虚拟环境(macOS和Linux上) |
deactivate | 退出虚拟环境 |
其它命令(不常用) | 描述 |
---|---|
pip check | 检查当前环境的包是否存在问题 |
pip search query | 搜索包含指定关键字的包 |
pip download package_name | 下载指定包的源代码,但不安装 |
pip install --user package_name | 在用户级别安装包,而不是全局或虚拟环境 |
pip install --no-cache-dir package_name | 安装包时禁用缓存,用于解决一些安装问题 |
7.3.4 conda
Miniconda、Anaconda、conda文档
venv 是 Python 的标准库中自带的虚拟环境管理工具,只包含与 Python 环境相关的必要组件。这使得它适合于创建纯粹的 Python 环境,即不支持非Python语言的包。所以目前一般是使用conda来管理虚拟环境。
conda 是一个跨平台的虚拟环境管理器,不仅支持 Python,还支持其他编程语言,也可以管理系统依赖项,目前有两个版本——Miniconda和Anaconda。前者只有几百M,是最小化版本,只包括Conda和Python,用户可以自定义需要安装的其它包。而后者有5、6G,预装了许多包,适用于各种数据科学任务。
以下是一些常用的conda命令:
conda包管理命令 | 描述 |
---|---|
conda create --name myenv python=3.8 | 创建名为myenv的虚拟环境,指定python版本为3.8 |
conda activate myenv source activate myenv | 激活虚拟环境(windows) 激活虚拟环境(macOS和Linux) |
conda install package_name | 在激活的虚拟环境中安装Python包 |
conda list | 列出当前虚拟环境中已安装的包 |
conda deactivate | 停用当前虚拟环境 |
conda env export > environment.yml | 导出当前虚拟环境的配置到一个YAML文件 |
conda env create -f environment.yml | 根据YAML文件创建虚拟环境 |
conda remove --name myenv --all | 删除指定名称的虚拟环境及其所有包 |
conda search package_name | 搜索可用于安装的包 |
conda update --all | 升级当前虚拟环境中的所有包 |
当运行
conda虚拟环境管理命令 | 描述 |
---|---|
conda update conda | 升级conda本身 |
conda config --show | 显示conda的配置信息 |
conda env list | 列出所有已创建的虚拟环境 |
conda info --env | 显示当前虚拟环境的详细信息 |
conda config --set auto_activate_base false | 禁用默认激活基础环境(默认情况下会自动激活基础环境) |
conda config --set auto_activate your_env_name | 设置your_env_name为默认的激活环境 |
默认情况下,conda自动激活base环境为当前使用环境。如果要更改某个环境为默认激活环境,你需要进行一下操作:
conda config --set auto_activate_base false # 禁用默认激活基础环境
conda config --set auto_activate your_env_name # 设置your_env_name为默认的激活环境
如果要恢复默认激活base环境,需要运行:
conda config --set auto_activate_base true # 恢复默认激活base环境
7.4 如何组织和管理大型项目中的模块与包
7.4.1 最佳实践
在大型项目中,组织和管理模块与包是非常重要的,它有助于代码的可维护性和可扩展性。以下是一些最佳实践:
1. 项目结构:
- 使用包(即包含
__init__.py
文件的目录)来组织相关的模块。包可以将相关模块放在一起,形成层次结构,使代码更有结构性。
2. 模块和包的命名:
- 给模块和包起一个清晰、有意义的名称,遵循Python的命名约定。避免使用与Python内置模块或库相同的名称,以防止命名冲突。
- 使用有描述性的变量、函数和类名,以提高代码的可读性。
3. 文档:
- 为模块、函数和类编写文档字符串(docstrings)。文档字符串应解释模块或代码的用途、输入参数、返回值等信息。这有助于其他开发人员理解和使用您的代码。
- 使用工具如Sphinx来生成文档,以便更轻松地维护和分享文档。
- 维护更新的文档,包括项目的使用方法、配置和安装说明。
文档字符串的说明可参考《python3.11教程1》4.6章
# numpy.py"""
NumPy is the fundamental package for scientific computing in Python.
It provides support for arrays, mathematical functions, linear algebra, and more.For more information, visit: https://numpy.org
"""import numpy as npdef create_array(shape, dtype=float):"""Create a new array of the given shape and data type.Parameters:shape (tuple): The shape of the array.dtype (type): The data type of the elements in the array (default is float).Returns:ndarray: A new NumPy array."""return np.zeros(shape, dtype=dtype)
4. 版本控制:
Git官方文档、Git中文教程、Atlassian Git教程
- 尽量避免模块之间的循环依赖。循环依赖可能导致难以调试和维护的问题。
- 使用版本控制系统(如Git)来跟踪和管理代码的变化。这有助于团队合作、版本控制和错误修复。
- 使用合适的版本号管理约定(如Semantic Versioning)来管理您的项目的版本。
5. 自动化构建和测试:
- pytest官方文档、W3Cschool《pytest教程》、realpython网教程《Effective Python Testing With Pytest》
- bilibili视频 及 视频博客——pytest 框架
- 编写单元测试来验证模块和函数的正确性。这有助于捕获潜在的错误,并确保代码在修改后仍然正常工作。
- 使用测试框架(如unittest或pytest)来自动运行测试。
6. 依赖管理:
- 使用依赖管理工具(如pip或conda)来管理项目的依赖关系。这有助于确保项目在不同环境中的一致性。
- 使用虚拟环境来隔离不同项目的依赖,确保项目使用的库与其他项目不会发生冲突。
7. 可扩展性和性能优化:
- 在设计项目时,考虑性能和可扩展性。选择适当的数据结构和算法,以便项目能够在处理大量数据时保持高效。
8. 团队协作:
- 如果您在团队中工作,请遵循共同的编码约定和工作流程。使用代码审查来确保代码质量。
7.4.2 Sphinx
Sphinx 是一个用于生成文档的工具,特别是用于编写和发布Python项目的文档。它是一个强大的文档生成器,支持多种输出格式,包括HTML、PDF、ePub等,以及集成了自动化的构建工具。Sphinx 最初由Python社区创建,但现在已广泛用于其他编程语言和项目的文档生成。以下是 Sphinx 的一些主要特点和用途:
-
结构化文档:Sphinx 使用一种称为reStructuredText(或简称 reST)的标记语言,允许您编写结构化的文档。这使得文档易于阅读、维护和版本控制。
-
自动索引:Sphinx 可以自动生成文档的索引、目录和交叉引用,使用户能够轻松导航文档。
-
多种输出格式:Sphinx 支持多种输出格式,包括HTML、PDF、ePub、man页、LaTeX等。
-
扩展性:Sphinx 具有丰富的扩展和插件系统,允许您自定义文档生成的过程,添加自定义样式和功能。
-
集成版本控制:Sphinx 可以与版本控制系统(如Git)集成,使您能够轻松将文档与代码同步,以确保文档的实时性。
-
支持多语言:Sphinx 支持多语言文档,允许您为不同的受众创建多语言版本的文档。
-
应用广泛:Sphinx 在许多开源项目中广泛使用,包括Python自身的官方文档、Django、numpy、pandas等。
总的来说,Sphinx 是一个功能强大的文档生成工具,特别适用于编写和发布Python项目的文档。它的灵活性和丰富的功能使其成为开发者、项目维护者和技术作者的首选工具之一。以下是一些关于如何使用 Sphinx 的具体教程、博客和示例项目:
-
Sphinx 官方文档
Sphinx 的官方文档是使用 Sphinx 编写的,它包含了完整的 Sphinx 使用指南。这是开始使用 Sphinx 的最佳起点。
-
Real Python Course: Documenting Python Projects With Sphinx and Read the Docs
在本视频系列中,将使用 Sphinx ( Python 的实际标准)从头开始创建项目文档、将代码存储库连接到 Read The Docs,以自动生成和发布代码文档。
-
The Sphinx Book
这是一本关于如何使用 Sphinx 编写书籍和长篇文档的免费在线书籍。它提供了详细的步骤和示例。
-
Sphinx Gallery
Sphinx Gallery 是一个示例项目,展示了如何使用 Sphinx 来创建一个包含代码示例、文档和说明的画廊。这对于展示您的代码如何工作非常有用。
八、 I/O系统(文件管理)
8.1 I/O
简介
文件输入和输出,通常缩写为文件I/O,是计算机编程中一个重要的概念。它涉及到将数据从程序读取到文件(输入)或从文件写入到程序(输出)。文件I/O对于存储和检索数据以及与外部世界进行交互非常关键。
文件I/O对于许多任务至关重要,例如:
-
数据持久性: 文件是一种持久性存储方法,可以将数据保存在磁盘上,以便在程序重新运行时保留数据。
-
数据共享: 文件允许不同的程序或多个实例之间共享数据。多个程序可以读取和写入同一个文件。
-
数据备份: 文件允许您创建数据的备份,以防数据丢失或损坏。
-
外部数据交换: 您可以使用文件I/O将数据与其他应用程序或系统进行交换。这在数据导入和导出时非常有用。
-
记录日志: 许多应用程序使用文件来记录日志信息,以帮助故障排除和监视应用程序的运行情况。
以下是一些基本的文件I/O操作:
-
使用
open()
函数打开文件。 -
使用
.read()
方法从文件中读取数据。 -
使用
.write()
方法将数据写入文件。 -
使用
with
语句来自动关闭文件,以确保资源的正确管理。
8.2 读写文本、二进制文件
官方文档:open函数、 with 上下文管理器
对于文本或二进制文件,我们可以使用open、read和write函数来进行读写,下面是一个简单的示例:
# 打开一个文本文件以供写入
with open("example.txt", "w") as file:file.write("这是一个示例文本。")
8.2.1 open函数
open函数常用于打开文件,其语法为:
open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
常用参数解析:
-
file
(必需):这是要打开的文件的名称(包括路径),可以是相对路径或绝对路径。如果文件不存在,根据所选的模式来操作。 -
mode
(可选):这是文件打开的模式,它表示您要对文件执行的操作。默认是只读模式(‘r’)。
模式 | 描述 |
---|---|
'r' | 只读模式,文件只能被读取(默认模式)。 |
'w' | 写入模式,如果文件存在,则截断文件并写入(覆盖原先内容)。如果文件不存在,则创建新文件并写入 |
'a' | 追加模式,用于在文件末尾添加内容。如果文件不存在,则创建新文件。 |
'x' | 独占创建模式,文件不存在时创建新文件。如果文件已存在,则抛出错误 |
'b' | 二进制模式,与上述模式结合使用,以指示以二进制格式打开文件(例如:‘rb’、‘wb’、‘ab’)。 |
't' | 文本模式(默认模式)。。与上述模式结合使用,以指示以文本模式打开文件(例如:‘rt’、‘wt’、‘at’) |
'+' | 读写模式,用于同时读取和写入文件。 |
# 写入二进制文件
with open("new_image.jpg", "wb") as new_binary_file:new_binary_file.write(image_data)
'+'
是读写模式,可以在同一文件上执行读取和写入操作,而不必先关闭文件再重新打开,适用于需要读取和更新文件内容的情况。例如:
example ='Line 1: This is the first line.\n''Line 2: This is the second line.'# 以读写模式打开空白文件
with open("example.txt", "w+") as file:content = file.read()print("原始内容:", content)file.write(example) # 在文件中写入新数据file.seek(0) # 回到文件开头updated_content=file.read() # 读取更新后的内容print(updated_content)
请注意,使用
'+'
模式时,要小心处理文件指针的位置以确保读取和写入操作发生在您希望的位置。
-
encoding
(可选):用于文本文件的字符编码。默认情况下,Python将使用系统默认编码。常见的编码包括'utf-8'
、'ascii'
等。 -
errors
(可选):处理编码错误的方式,默认是None
,即使用默认错误处理方式。
error选项 | 说明 |
---|---|
'strict' | 默认选项,表示严格处理编码错误,遇到无法解码的字节序列将引发UnicodeDecodeError 异常。 |
'ignore' | 忽略无法解码的字节序列,不会引发异常(无法解码的部分将被丢弃)。 |
'replace' | 使用 Unicode 替代字符 U+FFFD (�)来替换无法解码的字节。 |
'xmlcharrefreplace' | 使用 XML 字符引用来替换无法解码的字节,对于生成包含无效字符的 XML 数据很有用 |
'backslashreplace' | 使用反斜杠和十六进制编码的字节值来替换无法解码的字节。 |
'namereplace' | 使用 Unicode 转义序列来替换无法解码的字节,这样可以保留无效字符的名称信息。 |
opener
(可选):自定义打开文件的函数,例如:
# 使用自定义的打开函数my_opener打开文件
def my_opener(file, flags):return os.open(file, flags)file = open("example.txt", "r", opener=my_opener)
8.2.2 文件指针和文件截断(seek&truncate)
文件定位和截断是处理日志文件、配置文件、数据库文件等常见用例中的重要工具。它们允许您以灵活的方式管理文件的内容。
- seek函数
在 Python 中,文件指针是与文件关联的位置标识符,它指示了在文件中读取或写入数据时的当前位置。文件指针是一个整数,表示文件中的字节偏移量,其语法为:
file.seek(offset, whence)
offset
:一个整数,表示要移动的字节偏移量,默认为0。whence
:一个整数,表示相对位置,选项为:0
表示相对于文件的开头(默认值)。1
表示相对于文件指针的当前位置。2
表示相对于文件的末尾。
文件打开时文件指针默认处于文件开头,你也可以自由设置:
# 将文件指针移动到文件开头的第 100 字节处
file.seek(100, 0)# 将文件指针从当前位置向后移动 50 字节
file.seek(50, 1)# 将文件指针移动到文件末尾前的倒数第 200 字节处
file.seek(-200, 2)
- truncate函数
文件截断是指删除文件中的部分内容,使文件变得更短或清空文件,你可以使用truncate
来执行此操作,其语法为:
file.truncate(size)
其中,size表示截断时指定的大小(字节单位)。如果省略size参数,则文件将被截断为当前文件指针位置之前的大小,例如:
with open("file.txt", "r+") as file:file.truncate(50) # 截断文件为前50个字节
- 示例:在文件中插入数据
with open("file.txt", "r+") as file:# 移动文件指针到位置 30(假设文件足够长)file.seek(30)# 读取文件中剩余的内容remaining_data = file.read()# 回到位置 30 并插入新文本file.seek(30)file.write("插入的新文本 ")# 写入原始内容file.write(remaining_data)
这将在文件的指定位置插入新文本,并保留原始内容。
- 注意事项
-
使用
seek()
和truncate()
时,请小心不要超出文件的范围,以免发生错误。 -
在使用
truncate()
时,文件必须以可写入(“w"或"r+”)模式打开。否则,将引发UnsupportedOperation
异常。 -
文件截断是不可逆的操作,删除的数据将无法恢复。谨慎使用。
8.2.3 读写函数(read、write)
以下是Python中的文件读写函数:
方法 | 描述 | 参数 |
---|---|---|
read(size) | 读取整个文件的内容为,返回一个字符串。 | size可选,指定要读取的最大字节数。未指定时默认读取整个文件。 |
readline(size) | 逐行读取文件的内容,即每次读取一行。 | size可选,指定一行中要读取的最大字节数。未指定时默认读取整行内容。 |
readlines(hint) | 默认读取整个文件的内容,并将每行存储为列表中的一个元素。 | hint可选,含义同上 |
for 循环逐行读取 | 使用 for 循环逐行读取文件的内容。 | |
write(str) | 根据选择的模式,将指定的字符串写入文件的当前位置。 | write 函数没有额外参数 |
close | 关闭文件,释放文件资源并确保数据被保存。 |
read和readlines的区别:
- read(size):读取前size个字节的数据,不关心行的分隔符,最后返回一个字符串。另外文件指针将保持在读取数据之后的位置。
- readlines(size):读取前size个字节的数据,包含分隔符(通常是换行符
\n
),返回字符串列表(每一行)。最后,文件指针将移到下一个未读行的开头。
示例:
"""
example.txt
Line 1: This is the first line.
Line 2: This is the second line.
"""file = open('example.txt', 'r')
data1 = file.read(20) # 读取前 20 个字节,结果:"Line 1: This is the "
data2 = file.readlines(30) # 读取前 30 个字节,结果:["first line.\n", "Line 2: This is the second line."]file.close()
8.2.4 上下文管理器(with)
官方文档: with 上下文管理器
使用上下文管理器非常简单,只需在 with
语句中创建并使用它即可。下面是一个使用上下文管理器的示例,以打开和关闭文件为例:
# 使用上下文管理器自动关闭文件
with open("example.txt", "r") as file:content = file.read()print(content)# 在此处文件已自动关闭,无需手动关闭
在这个示例中,open()
函数返回一个文件对象,它是一个上下文管理器。当进入 with
代码块时,__enter__()
方法被调用,文件被打开。当代码块执行完毕后,无论正常执行还是出现异常,__exit__()
方法都会被调用,确保文件被正确关闭。
你还可以创建自定义的上下文管理器,以管理其他资源(如数据库连接、网络连接等)。要创建自定义上下文管理器,只需定义一个类,并实现 __enter__()
和 __exit__()
方法。以下是一个示例:
# 创建MyContextManager类实现一个简单的上下文管理器
class MyContextManager:def __enter__(self):print("Entering the context")# 在此处可以初始化资源return self # 返回一个对象(可选)def __exit__(self, exc_type, exc_value, traceback):print("Exiting the context")# 在此处进行清理操作,如关闭资源# 使用自定义上下文管理器
with MyContextManager() as cm:print("Inside the context")# 在此处自定义上下文管理器的__exit__()方法被调用,进行资源清理
上下文管理器是一个非常强大和有用的Python功能,它确保了资源的正确分配和释放,使代码更加健壮和可维护。无论是使用内置的上下文管理器还是创建自定义的上下文管理器,都可以提高代码的可读性和可维护性。
8.3 读写excel/csv文件
参考pandas官方文档《Input/output》、openpyxl官方文档、xlrd官方文档
前面讲的都是读写文本文件和二进制文件,如果要处理excel或者csv文件,可以使用pandasku、openpyxl库或者xird,下面进行简单介绍。
8.3.1 pandas读写excel/csv文件
pandas 可以读取的文件格式有很多,下面一一介绍。
1. 读取 csv, excel, txt 文件
pandas.read_csv(filepath, *, sep=_NoDefault.no_default, delimiter=None, header='infer', names=_NoDefault.no_default, index_col=None, usecols=None, dtype=None, engine=None, converters=None, true_values=None, false_values=None, skipinitialspace=False, skiprows=None, skipfooter=0, nrows=None, na_values=None, keep_default_na=True, na_filter=True, verbose=False, skip_blank_lines=True, parse_dates=None, infer_datetime_format=_NoDefault.no_default, keep_date_col=False, date_parser=_NoDefault.no_default, date_format=None, dayfirst=False, cache_dates=True, iterator=False, chunksize=None, compression='infer', thousands=None, decimal='.', lineterminator=None, quotechar='"', quoting=0, doublequote=True, escapechar=None, comment=None, encoding=None, encoding_errors='strict', dialect=None, on_bad_lines='error', delim_whitespace=False, low_memory=True, memory_map=False, float_precision=None, storage_options=None, dtype_backend=_NoDefault.no_default)[source]
df_csv = pd.read_csv('data/my_csv.csv')
df_txt = pd.read_table('data/my_table.txt')
df_excel = pd.read_excel('data/my_excel.xlsx')
这里有一些常用的公共参数:
filepath
:可以是文件路径或者URL,例如本地文件file://localhost/path/to/table.csv。sep
:分割符。pd.read_csv
默认使用逗号作为分隔符,pd.read_table
默认使用制表符\t
作为分隔符。header='infer'
: 指定用作列名的行号,默认为0,表示第一行。可以设置header=None
不使用列名。names
:自定义列名,以列表形式提供。如果设置了header=None
,则可以使用该参数index_col
:表示把某一列或几列作为列索引,可以是整数、字符串或列表usecols
:表示要读取的列,可以是列号、列名或者列名的列表,默认读取所有的列parse_dates
:指定要解析为日期时间的列,可以是列号或列名的列表date_parser
:使用自定义函数解析日期时间列nrows
:表示读取的数据行数。skiprows
:要跳过的行数(从文件顶部开始计算)skipfooter
:要从文件底部跳过的行数(不支持所有的解析器)na_values
:用于将特定值识别为缺失值的列表或字典
下面是具体的示例:
# 1.读取txt文件,不设置列名
pd.read_table('data/my_table.txt', header=None)
Out[10]: 0 1 2 3 4
0 col1 col2 col3 col4 col5
1 2 a 1.4 apple 2020/1/1
2 3 b 3.4 banana 2020/1/2
3 6 c 2.5 orange 2020/1/5
4 5 d 3.2 lemon 2020/1/7# 2.设置索引列,并跳过前两行
pd.read_csv('data/my_csv.csv', index_col=['col1', 'col2'],skiprows=[0, 1])
Out[11]: col3 col4 col5
col1 col2
6 c 2.5 orange 2020/1/5
5 d 3.2 lemon 2020/1/7# 3.只读取前两列,并设置列名
pd.read_table('data/my_table.txt', usecols=['col1', 'col2'],header=None,names=[列1','列2'])
Out[12]: 列1 列2
0 2 a
1 3 b
2 6 c
3 5 d# 4.使用自定义函数解析指定'col5'的日期解析格式,只读前两行
date_parser = lambda x: pd.to_datetime(x, format='%Y-%m-%d')
pd.read_csv('data/my_csv.csv', parse_dates=['col5'], date_parser=date_parser,nrows=2)
Out[13]: col1 col2 col3 col4 col5
0 2 a 1.4 apple 2020-01-01
1 3 b 3.4 banana 2020-01-02# 5. 将文件中的'N/A', 'NA'字符视为缺失值,并替换为NaN
pd.read_csv('data/my_table.txt',header=None,na_values=['N/A', 'NA'])
另外read_excel
还有一些常用参数:
sheet_name
:指定要读取的工作表名称,默认为0,表示第一个工作表。可以使用字符串(工作表名称)或整数(工作表索引)。engine
:指定要使用的解析引擎,例如’xlrd’或’openpyxl’。默认根据文件扩展名自动选择
在读取 txt 文件时,经常遇到分隔符非空格的情况, read_table 有一个分割参数 sep ,它使得用户可以自定义分割符号,进行 txt 数据的读取。例如,下面的读取的表以 |||| 为分割:
pd.read_table('data/my_table_special_sep.txt')
Out[15]: col1 |||| col2
0 TS |||| This is an apple.
1 GQ |||| My name is Bob.
2 WT |||| Well done!
上面的结果显然不是理想的,这时可以使用 sep ,同时需要指定引擎为 python
pd.read_table('data/my_table_special_sep.txt',sep=' \|\|\|\| ', engine='python')
Out[16]: col1 col2
0 TS This is an apple.
1 GQ My name is Bob.
2 WT Well done!
3 PT May I help you?
在使用
read_table
的时候需要注意,参数sep
中使用的是正则表达式,因此需要对|
进行转义变成\|
,否则无法读取到正确的结果。
2. 写入csv, excel, txt 文件
pandas 中没有定义 to_table 函数,但是 to_csv 可以保存为 txt 文件(也可以保存csv文件),并且允许自定义分隔符,常用制表符 \t
分割:
# 当索引没有特殊意义的时候,可以使用index=False 去除索引
df.to_csv('data/my_txt_saved.txt', sep='\t', index=False)
如果想要把表格快速转换为 markdown 和 latex 语言,可以使用 to_markdown
和 to_latex
函数(需要先安装 tabulate 包)。
print(df_csv.to_markdown())
col1 | col2 | col3 | col4 | col5 | |
---|---|---|---|---|---|
0 | 2 | a | 1.4 | apple | 2020/1/1 |
1 | 3 | b | 3.4 | banana | 2020/1/2 |
2 | 6 | c | 2.5 | orange | 2020/1/5 |
3 | 5 | d | 3.2 | lemon | 2020/1/7 |
print(df_csv.to_latex())
\begin{tabular}{lrlrll}
\toprule
{} & col1 & col2 & col3 & col4 & col5 \\
\midrule
0 & 2 & a & 1.4 & apple & 2020/1/1 \\
1 & 3 & b & 3.4 & banana & 2020/1/2 \\
2 & 6 & c & 2.5 & orange & 2020/1/5 \\
3 & 5 & d & 3.2 & lemon & 2020/1/7 \\
\bottomrule
\end{tabular}
8.3.2 openpyxl库
openpyxl 是一个非常强大和广泛使用的库。它允许你读取、写入和操作Excel文件(.xlsx 格式)。使用之前,需要进行安装:pip install openpyxl
。下面列举openpyxl的主要操作:
操作/函数 | 描述 |
---|---|
openpyxl.load_workbook(filename) | 打开一个Excel工作簿并返回工作簿对象。 |
workbook.create_sheet(title) | 创建一个新的工作表并返回工作表对象。 |
workbook.active | 获取或设置当前活动的工作表。 |
workbook.sheetnames | 返回工作簿中所有工作表的名称列表。 |
worksheet.cell(row, column) | 获取或设置指定行列的单元格。 |
worksheet.iter_rows() | 遍历工作表中的行,返回单元格值的生成器。 |
worksheet.iter_cols() | 遍历工作表中的列,返回单元格值的生成器。 |
worksheet.title | 获取或设置工作表的名称。 |
worksheet.max_row | 获取工作表中的最大行数。 |
worksheet.max_column | 获取工作表中的最大列数。 |
worksheet['A1'] | 使用字母和数字索引获取单元格的值。 |
worksheet.append([data]) | 向工作表追加一行数据。 |
worksheet.delete_rows(index, count) | 删除工作表中指定索引位置的行。 |
worksheet.insert_rows(index, count) | 在指定位置插入指定数量的空白行。 |
worksheet.delete_cols(index, count) | 删除工作表中指定索引位置的列。 |
worksheet.insert_cols(index, count) | 在指定位置插入指定数量的空白列。 |
workbook.save(filename) | 保存工作簿到指定文件。 |
workbook.remove(sheet) | 从工作簿中移除指定工作表。 |
workbook.copy_worksheet(sheet) | 复制工作表到同一工作簿或另一个工作簿。 |
import openpyxl# 打开一个现有的工作簿
workbook = openpyxl.load_workbook('example.xlsx')# 选择工作簿中的工作表(通过名称)
worksheet = workbook['Sheet1']# 读取单元格数据
value = worksheet.cell(row=1, column=1).value# 写入单元格数据
worksheet.cell(row=2, column=2, value='Hello, World!')# 保存工作簿
workbook.save('new_example.xlsx')# 创建新的工作表
new_sheet = workbook.create_sheet('NewSheet')# 遍历工作表数据
print('工作表数据:')
for row in worksheet.iter_rows(values_only=True):print(row)
8.3.3 xlrd库(打开加密excel)
xlrd 也是一个用于读取 Excel 文件的 Python 库,主要函数如下:
操作/函数 | 描述 |
---|---|
xlrd.open_workbook(filename) | 打开一个 Excel 工作簿并返回工作簿对象。 |
workbook.sheet_names() | 获取工作簿中所有工作表的名称。 |
workbook.sheet_by_name(name) | 根据工作表名称选择工作表。 |
workbook.sheet_by_index(index) | 根据索引选择工作表。 |
worksheet.cell_value(row, col) | 读取指定行列的单元格内容。 |
worksheet.nrows | 获取工作表的行数。 |
worksheet.ncols | 获取工作表的列数。 |
worksheet.row(row_num) | 返回指定行的所有单元格内容(以列表形式)。 |
worksheet.col(col_num) | 返回指定列的所有单元格内容(以列表形式)。 |
xlrd.xldate_as_datetime(date, datemode) | 将 Excel 日期值转换为 Python 的 datetime 对象。 |
workbook.close() | 关闭工作簿。 |
# 导入所需的库和模块
import pandas as pd
import numpy as np
import os
from xlrd import *
import win32com.client
import sys# 设置要打开的Excel文件的文件路径
filename = '缩孔数据库/2023缩孔统计更新至9-4.xlsm'
color = ['QAC', 'G41', 'QAB', 'KAD'] # 设置要查找的颜色
xlApp = win32com.client.Dispatch("Excel.Application") # 创建一个Excel应用程序对象
password = 'xxxxxxxx' # Excel文件的密码(如果有密码保护的话)# 使用只读模式打开工作簿
# Format=None表示让 Excel 自动识别文件格式。你也可以明确指定,例如 Format=1 表示打开的是 xls 格式文件。
xlwb = xlApp.Workbooks.Open(Filename=os.path.abspath(filename),ReadOnly=True,Format=None,Password=password)xlws = xlwb.Sheets(3) # 选择工作簿中的第3张工作表(索引从1开始)
cols = 15 # 选择要读取的列数
rows = xlws.UsedRange.Rows.Count # 获取工作表的行数# 从工作表中读取(1, 1)到(rows, cols)之间的单元格,其实就是前15列
content = list(xlws.Range(xlws.Cells(1, 1), xlws.Cells(rows, cols)).Value)# 将读取的数据转换为Pandas DataFrame
df = pd.DataFrame(content)
8.4 os模块
8.4.1 os模块常用函数
官方文档:《os — 多种操作系统接口》、《os.path — 常用路径操作》
如果你只是想读写一个文件,请参阅 open(),如果你想操作文件路径,请参阅 os.path 模块,如果你想读取通过命令行给出的所有文件中的所有行,请参阅 fileinput 模块。 为了创建临时文件和目录,请参阅 tempfile 模块,对于高级文件和目录处理,请参阅 shutil 模块。
os
模块是 Python 的标准库之一,提供了与操作系统交互的功能。它允许您执行与文件系统、目录、文件路径等相关的操作。以下是 os
模块的一些主要功能:
文件和目录操作函数 | 描述 |
---|---|
os.mkdir(path) | 创建一个新的目录。 |
os.rmdir(path) | 删除一个空目录。 |
os.remove(path) | 删除文件。 |
os.rename(src, dst) | 重命名文件或目录。 |
os.getcwd() | 返回当前工作目录。 |
os.listdir(path) | 返回目录中的文件和子目录的列表。 |
os.walk(top, topdown=True, onerror=None, followlinks=False) | 生成目录树中的文件名。 |
os.chmod(path, mode) | 更改文件或目录的权限。 |
os.stat(path) | 获取文件或目录的状态信息。 |
路径操作函数 | 描述 |
---|---|
os.path.join(path1, path2, ...) | 连接路径的各个部分,以创建完整路径。 |
os.path.abspath(path) | 返回绝对路径。 |
os.path.exists(path) | 检查文件或目录是否存在。 |
os.path.isdir(path) | 检查路径是否为目录。 |
os.path.isfile(path) | 检查路径是否为文件。 |
os.path.basename(path) | 返回路径中的文件名。 |
os.path.dirname(path) | 返回路径中的目录名。 |
os.path.split(path) | 分割路径,返回目录名和文件名的元组。 |
环境变量函数 | 描述 |
---|---|
os.environ | 包含系统环境变量的字典。 |
os.getenv(key, default) | 获取指定环境变量的值。 |
系统命令函数 | 描述 |
---|---|
os.name | 返回操作系统的名称(例如,‘posix’ 或 ‘nt’)。 |
os.uname() | 返回有关当前系统的详细信息(仅在 POSIX 系统上可用)。 |
os.system(command) | 在子shell中执行系统命令。 |
os.spawn*() | 生成新进程。 |
os.kill(pid, signal) | 终止进程 |
8.4.2 os.walk函数
os.walk()
是一个非常实用的函数,用于在目录树中遍历文件和子目录。它返回一个生成器,该生成器产生三元组 (dirpath, dirnames, filenames)
,其中:
dirpath
:当前目录的路径。dirnames
:当前目录下的子目录列表,如果没有子目录,则返回空列表filenames
:当前目录下的文件列表。
下面是一个详细说明 os.walk()
用法的示例,假设我们有以下目录结构:
my_folder
│
├── dir1
│ ├── file1.txt
│ └── file2.txt
│
├── dir2
│ ├── sub_dir
│ │ ├── file3.txt
│ │ └── file4.txt
│ └── file5.txt
│
└── file6.txt
我们可以使用 os.walk()
遍历这个目录树并打印出每个目录中的子目录和文件:
import os# 设置要遍历的根目录
root_directory = 'my_folder'# 使用 os.walk() 遍历目录树
for dirpath, dirnames, filenames in os.walk(root_directory):# 打印当前目录路径print(f"Current Directory: {dirpath}")# 打印当前目录下的子目录print("Subdirectories:")for dirname in dirnames:print(f" - {dirname}")# 打印当前目录下的文件print("Files:")for filename in filenames:print(f" - {filename}")# 打印一个分隔线print("-" * 40)
运行这个代码会产生如下输出:
Current Directory: my_folder
Subdirectories:- dir1- dir2
Files:- file6.txt
----------------------------------------
Current Directory: my_folder\dir1
Subdirectories:
Files:- file1.txt- file2.txt
----------------------------------------
Current Directory: my_folder\dir2
Subdirectories:- sub_dir
Files:- file5.txt
----------------------------------------
Current Directory: my_folder\dir2\sub_dir
Subdirectories:
Files:- file3.txt- file4.txt
----------------------------------------
8.5 shutil 模块(移动、复制、压缩文件)
参考《shutil — 高阶文件操作》
shutil
模块是Python标准库中的一个强大工具,用于文件和目录操作。它提供了许多函数,可用于复制、移动、删除文件和目录,以及执行各种文件操作任务,以下是其主要用法:
方法 | 描述 | 示例 |
---|---|---|
shutil.copy(src, dst) | 复制文件从源路径到目标路径。 | shutil.copy('source.txt', 'destination.txt') |
shutil.move(src, dst) | 移动文件或重命名文件。 | shutil.move('old_name.txt', 'new_name.txt') |
shutil.copytree(src, dst) | 递归复制整个文件夹及其内容。 | shutil.copytree('source_folder', 'destination_folder') |
shutil.rmtree(path) | 递归删除整个目录树,包括所有文件和子目录。 | shutil.rmtree('folder_to_delete') |
shutil.make_archive(base_name, format) | 创建归档文件,例如 ZIP 文件。 | hutil.make_archive(archive_name, format='zip', root_dir='folder_to_compress') |
shutil.unpack_archive(filename, extract_dir) | 解压缩归档文件。 | shutil.unpack_archive('my_archive.zip', 'extracted_folder') |
归档函数语法为:
shutil.make_archive(base_name, format, root_dir=None, base_dir=None)
参数含义:
base_name
:归档文件的基本名称,不包括文件扩展名。例如,如果设置为'my_archive'
,则将创建'my_archive.zip'
或'my_archive.tar.gz'
等文件。format
:归档文件的格式,通常是字符串,可以是'zip'
、'tar'
、'gztar'
、'bztar'
、'xztar'
等。
‘gztar’:gzip 压缩的 tar 归档文件。
‘bztar’:bzip2 压缩的 tar 归档文件。
‘xztar’:xz 压缩的 tar 归档文件root_dir
(可选):要归档的根目录,如果不提供,默认为当前工作目录。base_dir
(可选):要归档的基本目录,如果提供,将在root_dir
下创建一个子目录,并将其内容归档。
tar是未压缩的tar 归档文件,后三者分别是gzip格式、bzip2格式和xz格式压缩的tar文件。
下面是一个示例假设有以下目录结构:
my_project/├── source/│ ├── file1.txt│ ├── file2.txt│ └── subfolder/│ └── file3.txt└── other_folder/└── file4.txt
现在用zip格式只归档source和other_folder目录到指定目录下,代码可以写为:
import shutil# 源目录的根目录
source_root_dir = 'my_project/'# 要归档的子目录列表
subdirectories_to_archive = ['source/', 'other_folder/']# 目标位置
destination_dir = 'destination_directory/'# 归档文件的名称和格式
archive_name = 'my_archive'
format = 'zip'# 创建 ZIP 归档文件,指定 root_dir 为源目录,base_dir 为子目录列表
shutil.make_archive(archive_name, format, root_dir=source_root_dir, base_dir=subdirectories_to_archive
)# 将归档文件移动到目标位置
shutil.move(f'{archive_name}.{format}', destination_dir) # 解压到source目录下
shutil.unpack_archive(archive_file, 'my_project/source/')
8.6 Python数据的序列化
Pyhon官方文档:json模块、pickle模块
8.6.1 数据的序列化和反序列化
前者介绍的read、write这些方法,都是进行字符串的读取,即使是数字,也是转成字符串格式,而如果碰到嵌套列表和字典等更复杂的数据类型时,手动解析将会变得非常复杂。这就涉及到数据的序列化和反序列化:
-
序列化(Serialization):
将数据从其原始数据结构(通常是Python对象)转换为一种可以在不同程序、不同计算机或不同时间之间传输或存储的格式的过程,通常转换为文本或二进制表示,以便能够保存到文件、发送到网络、存储在数据库中或在其他情况下传输和使用。
在Python中,常见的序列化方法包括使用JSON(JavaScript Object Notation)或Pickle(Python特定的序列化格式)等。 -
反序列化(Deserialization):将序列化后的数据重新还原为可以在程序中操作的Python对象,用于在程序中进一步处理数据。。
python提供了json
标准库,可以使用 JSON (JavaScript Object Notation)格式进行数据的交换。JSON数据是纯文本,易于阅读和编写,也易于解析和生成,非常适合处理复杂结构的数据,在Web开发、API通信以及配置文件中广泛使用。
8.6.2 json模块
Python的json
模块允许你序列化Python对象(将其转换为JSON格式)和反序列化JSON数据(将JSON数据转换为Python对象),其主要方法有:
json方法 | 描述 |
---|---|
json.dumps(obj) | 将Python对象序列化为JSON字符串 |
json.loads(json_str) | 将JSON字符串反序列化为Python对象 |
json.dump(obj, file) | 将Python对象序列化为JSON并保存到文件中 |
json.load(file) | 从文件中加载JSON数据并反序列化为Python对象 |
下面是示例代码:
# 将Python对象转换为JSON
import jsondata = {"name": "John","age": 30,"city": "New York"
}# 将Python字典转换为JSON字符串
json_data = json.dumps(data)# 保存JSON字符串到文件
with open("data.json", "w") as json_file:json.dump(data, json_file)
import json
# 从JSON字符串反序列化为Python字典
json_data = '{"name": "John", "age": 30, "city": "New York"}'
data = json.loads(json_data)# 从文件中加载JSON数据
with open("data.json", "r") as json_file:data = json.load(json_file)
8.6.3 pickle模块
pickle
是Python的一种序列化模块,它能够将Python对象转换为二进制格式,所以它可以序列化几乎所有Python对象,包括自定义类的实例和函数、模型等。以下是其常用的方法:
pickle模块方法 | 描述 |
---|---|
pickle.dumps(obj[, protocol]) | 将Python对象序列化为包含二进制数据的字符串 |
pickle.loads(bytes_object) | 从包含二进制数据的字符串中反序列化为Python对象 |
pickle.dump(obj, file[, protocol]) | 将Python对象序列化为二进制数据并保存到文件中 |
pickle.load(file) | 从文件中加载二进制数据并反序列化为Python对象 |
pickle.Pickler(file[, protocol]) | 创建一个Pickler对象,用于将对象序列化到文件或文件类中 |
pickle.Unpickler(file) | 创建一个Unpickler对象,用于从文件或文件类中反序列化对象 |
pickle.HIGHEST_PROTOCOL | 常量,表示pickle使用的最高协议版本(通常是最新的) |
上述列表中,可选参数protocol
用于指定序列化使用的协议版本,默认为最高版本。列表列举出三种序列化和反序列化方法,区别如下:
- pickle.dump:用于将Python对象序列化为二进制数据并保存到文件中。
- pickle.dumps:用于将Python对象序列化为包含二进制数据的字符串(不保存到文件)。
- pickle.Pickler:创建一个Pickler对象,可用于处理多个Python对象。
下面举例说明:
import pickle# 示例数据
data1 = {"name": "Alice","age": 25,"city": "London"
}data2 = {"name": "Bob","age": 30,"city": "New York"
}# 使用 pickle.dump 进行序列化,结果保存在文件中
with open("data.pkl", "wb") as pickle_file:pickle.dump(data1, pickle_file)# 使用 pickle.load 读取文件,进行对应的反序列化
with open("data.pkl", "rb") as pickle_file:loaded_data1 = pickle.load(pickle_file)'---------------------------------------------------------------'# 使用 pickle.dumps 进行序列化,结果赋值给一个变量
pickle_data = pickle.dumps(data2)# 使用 pickle.loads 反序列化这个变量
loaded_data2 = pickle.loads(pickle_data)'---------------------------------------------------------------'# 使用 pickle.Pickler 和 pickle.Unpickler 进行序列化和反序列化
with open("data.pkl", "wb") as pickle_file:pickler = pickle.Pickler(pickle_file) pickler.dump(data1) # 序列化数据1pickler.dump(data2) # 序列化数据2with open("data.pkl", "rb") as pickle_file:unpickler = pickle.Unpickler(pickle_file) loaded_data1_pickled = unpickler.load() # 反序列化数据1 loaded_data2_pickled = unpickler.load() # 反序列化数据2# 打印反序列化后的数据
print("Loaded Data 1:", loaded_data1)
print("Loaded Data 2:", loaded_data2)
print("Loaded Data 1 (Pickler):", loaded_data1_pickled)
print("Loaded Data 2 (Pickler):", loaded_data2_pickled)
Pickler
对象可以将多个序列化的对象存储在同一个文件中,Unpickler
对象在加载时会按顺序逐个读取和反序列化这些对象,所以上述代码中,会多次调用unpickler.load()
来逐个加载这些对象,并将它们分配给不同的变量。
总结: json和pickle的区别
-
JSON(JavaScript Object Notation)
- 用于文本序列化格式,适用于序列化简单的数据结构,如字典、列表、字符串和数字,人类更容易解读。
- 通用性强,可以在不同编程语言之间轻松交换数据。
- 安全性高,对一个不信任的JSON进行反序列化的操作本身不会造成任意代码执行漏洞。
-
Pickle
- Python特定的二进制序列化格式,可以用于序列化几乎所有Python对象,包括自定义类的实例和函数。
- pickle序列化是Python专用的,不适合与其他编程语言交互
- pickle可以加载包含恶意代码的数据,所以需要谨慎使用(只在信任的源中使用pickle)。
8.6.4 示例:使用pickle保存lightGBM模型&加载预测
见我的另一篇帖子《lightGBM实战》
相关文章:

Python3.11教程3:模块和包(pip/conda)、文件系统(os/ shutil/json/pickle/openpyxl/xlrd)
文章目录 七、模块和包7.1 模块7.1.1 模块搜索路径7.1.2 PYTHONPATH和sys.path7.1.2 模块的导入和常见错误7.1.3 模块的缓存机制7.1.4 __name__ 和 __main__ 函数 7.2 标准库7.3 包7.3.1 创建包7.3.2 导入包7.3.3 pip包管理器7.3.4 conda 7.4 如何组织和管理大型项目中的模块与…...

shell 脚本工具(三剑客)
第一个:awk awk 是一种强大的文本处理工具和编程语言,最初由 Alfred Aho、Peter Weinberger 和 Brian Kernighan 在20世纪70年代早期创建。awk 的名称来自于这三位创造者的姓氏的首字母。它在 Unix 和类 Unix 操作系统中广泛使用,用于处理、…...

基于微信小程序的智能垃圾分类回收系统,附源码、教程
博主介绍:✌程序员徐师兄、7年大厂程序员经历。全网粉丝30W、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 1 简介 视频演示地址: 基于微信小程序的智能垃圾分类回收系统,可作为毕业设计 小…...

【C++进阶】:AVL树(平衡因子)
AVL树 一.概念二.插入1.搜索二叉树2.平衡因子 三.旋转1.更新平衡因子2.旋转1.左单旋2.右单旋3.先右旋再左旋4.先左旋再右旋 四.完整代码 一.概念 二叉搜索树虽可以缩短查找的效率,但如果数据有序或接近有序二叉搜索树将退化为单支树,查找元素相当于在顺序表中搜索元…...

Python教程33:关于在使用zipfile模块,出现中文乱码的解决办法
zipfile是Python标准库中的一个模块,zipfile里有两个class, 分别是ZipFile和ZipInfo,用来创建和读取zip文件,而ZipInfo是存储的zip文件的每个文件的信息的。ZIP文件是一种常见的存档文件格式,它可以将多个文件和目录压缩为一个文件…...

【疑难杂症】使用xshell连接云服务器连接不上
目录 【1】使用xshell连接云服务器连接不上 【1.1】解决方法一 【1.2】解决方法二 【1】使用xshell连接云服务器连接不上 Centos7使用xshell连接提示"ssh服务器拒绝了密码 请再试一次"。 问题如图所示,新安装了一台Centos7服务器,使用ssh连…...

Qt MinGW / MSVC
MinGW/MSVC的关系 MinGW / MSVC.dll / .lib / .a 的关系 MinGW / MSVC Qt 中有两种方式编译:一种是MinGW ,另一种MSVC,是两种不同的编译器。 MinGW(Minimalist GNUfor Windows),它是一个可自由使用和自由发布的Windows特定头文件…...

【数学建模】数据预处理
为什么需要数据预处理 数学建模是将实际问题转化为数学模型来解决的过程,而数据预处理是数学建模中非常重要的一步。以下是为什么要进行数据预处理的几个原因: 数据质量:原始数据往往存在噪声、异常值、缺失值等问题,这些问题会对…...

VMware 安装 黑群晖7.1.1-42962 DS918+
本例的用的文件 1、ARPL 1.0beat 引导文件 vmdk格式: https://download.csdn.net/download/mshxuyi/88309308 2、DS918_42962.pat:https://download.csdn.net/download/mshxuyi/88309383 一、引导文件 1、创建一个虚拟机 2、下一步,选稍后…...

OpenCV(二十九):图像腐蚀
1.图像腐蚀原理 腐蚀操作的原理是将一个结构元素(也称为核或模板)在图像上滑动,并将其与图像中对应位置的像素进行比较。如果结构元素的所有像素与图像中对应位置的像素都匹配,那么该位置的像素值保持不变。如果结构元素的任何一个…...

【网络知识点】三次握手和四次挥手
文章目录 一、三次握手二、四次挥手 一、三次握手 三次握手的原理如下: 客户端向服务器发送一个SYN(同步)包,其中包含一个随机生成的初始序列号(ISN)。 服务器收到SYN包后,会发送一个SYNACK&…...

CSS整理
目录 CSS中的& 弹性(display:flex)布局 flex的对齐方式 justify-content align-items flex-wrap 弹性盒换行 flex:1 flex属性 flex-grow:项目的放大比例 flex-shrink:收缩 flex-basis:初始值ÿ…...

OpenCV 06(图像的基本变换)
一、图像的基本变换 1.1 图像的放大与缩小 - resize(src, dsize, dst, fx, fy, interpolation) - src: 要缩放的图片 - dsize: 缩放之后的图片大小, 元组和列表表示均可. - dst: 可选参数, 缩放之后的输出图片 - fx, fy: x轴和y轴的缩放比, 即宽度和高度的缩放比. - …...

Java 中的日期时间总结
前言 大家好,我是 god23bin,在日常开发中,我们经常需要处理日期和时间,日期和时间可以说是一定会用到的,现在总结下 Java 中日期与时间的基本概念与一些常用的用法。 基本概念 日期(年月日,某…...

创建10个线程并发执行(STL/Windows/Linux)
C并发编程入门 目录 STL 写法 #include <thread> #include <iostream> using namespace std;void thread_fun(int arg) {cout << "one STL thread " << arg << " !" << endl; }int main(void) {int thread_count 1…...

三、创建各个展示模块组件
简介 在文件 components 中创建轮播模块组件,引入App.vue展示。欢迎访问个人的简历网站预览效果 本章涉及修改与新增的文件:First.vue、Second.vue、Third.vue、Fourth.vue、Fifth.vue、App.vue、vite-env.d.ts、assets 一、修改vite-env.d.ts文件 /// <reference type…...

推荐一款程序员截图神器!
快来看一下程序员必备的一款截图工具 今天就来和大家说一下作为程序员必备截图神器,几乎每一个程序员都会设置开机自启,因为这个截图功能太太太好用了!!!只要你在键盘上按下F1就可以轻松截取整个屏幕,然后…...

无涯教程-JavaScript - IMCSC函数
描述 IMCSC函数以x yi或x yj文本格式返回复数的余割。 复数的余割定义为正弦的倒数。即 余割(z) 1 /正弦(z) 语法 IMCSC (inumber)争论 Argument描述Required/OptionalInumberA complex number for which you want the cosecant.Required Notes Excel中的复数只是简单…...

Ubuntu22.04 LTS 显卡相关命令
第一部分查看驱显卡信息 一、查看显卡型号 # -i表示不区分大小写 lspci | grep -i nvidia # 必须安装好nvidia驱动 nvidia-smi -L 二、查看显卡驱动版本 cat /proc/driver/nvidia/version 三、查看CUDA、cuDNN版本 # 或者 nvcc -V(两个显示的版本一致…...

《TCP/IP网络编程》阅读笔记--基于 TCP 的半关闭
目录 1--基于TCP的半关闭 1-1--TCP单方面完全断开的问题 1-2--shutdown()函数 1-3--半关闭的必要性 2--基于半关闭的文件传输程序 1--基于TCP的半关闭 1-1--TCP单方面完全断开的问题 Linux 系统中的 close 函数会将 TCP Socket 的连接完全断开,这意味着不能收…...

Rust的模块化
Rust的模块化要从Rust的入口文件谈起。 Rust的程序的入口文件有两个 如果程序类型是可执行应用,入口文件是main.rs;如果程序类型是库,入口文件是lib.rs; 入口文件中,必须声明本地模块,否则编译器在编译过…...

vmware设置桥接模式后ip设置
网络连接方式设置 找到虚拟机里机器的网络设置 左边是宿主机,右边是虚拟机,按照这个设置就可以上网了(IP指定一个没有占用的值,子网掩码和网关设置成一样的)就可以联网了。 over~~...

算法通关村第十七关:白银挑战-贪心高频问题
白银挑战-贪心高频问题 1. 区间问题 所有的区间问题,参考下面这张图 1.1 判断区间是否重叠 LeetCode252 https://leetcode.cn/problems/meeting-rooms/ 思路分析 因为一个人在同一时刻只能参加一个会议,因此题目的本质是判断是否存在重叠区间 将区…...

目标检测评估指标mAP:从Precision,Recall,到AP50-95
1. TP, FP, FN, TN True Positive 满足以下三个条件被看做是TP 1. 置信度大于阈值(类别有阈值,IoU判断这个bouding box是否合适也有阈值) 2. 预测类型与标签类型相匹配(类别预测对了) 3. 预测的Bouding Box和Ground …...

七大排序算法
目录 直接插入排序 希尔排序 直接选择排序 堆排序 冒泡排序 快速排序 快速排序优化 非递归实现快速排序 归并排序 非递归的归并排序 排序:所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作. 常见的排序算法有插入排序(直接插入…...

GitHub two-factor authentication
1. 介绍 登录 GitHub 官网,会提示要开启双因子认证。 但推荐的 APP 都是国外了,国内用不了。 可以使用 “腾讯身份验证器” 微信小程序。 2. 操作 开启双因子认证: 打开 “腾讯身份验证器” 微信小程序,扫描 GitHub 那个二维…...

un-app-手机号授权登录-授权框弹不出情况
前言 手机号授权是获取用户信息api停用之后,经常使用的api。但是此api也是有很多坑 手机号授权会出现调用不起来的情况,这是因为小程序后台没有进行微信认证导致的 手机号授权调用不起来-没有微信认证 来到小程序后台-设置-基本设置-下拉找到微信认证…...

手写Spring:第14章-自动扫描Bean对象注册
文章目录 一、目标:自动扫描Bean对象注册二、设计:自动扫描Bean对象注册三、实现:自动扫描Bean对象注册3.0 引入依赖3.1 工程结构3.2 Bean生命周期中自动加载包扫描注册Bean对象和设置占位符属性类图3.3 主力占位符配置3.4 定义拦截注解3.4.1…...

redux中间件的简单讲解
redux中间件 中间件的作用: 就是在 源数据 到 目标数据 中间做各种处理,有利于程序的可拓展性,通常情况下,一个中间件就是一个函数,且一个中间件最好只做一件事情 数据源 --------> 中间件 --------> 中间件 -…...

嵌入式开发-绪论
目录 一.什么是嵌入式 1.1硬件系统 1.2软件系统 二.嵌入式应用场景 2.1消费电子 2.1.1智能家居 2.1.2影音 2.1.3家用电器 2.1.4玩具游戏机 2.2通信领域 2.2.1对讲机 2.2.2手机 2.2.3卫星 2.2.4雷达 2.3控制领域 2.3.1机器人 2.3.2采集器PLC 2.4金融 2.4.1POS…...