一、说明
Python是一种通用且被广泛采用的编程语言,用于从数据分析到Web开发的所有内容。但是,随着 Python 项目复杂性的增加,跟踪所有移动部件并确保一切井井有条可能变得具有挑战性。
这就是了解 Python 文件结构的用武之地。在本文中,我们将回顾构建 Python 项目的一些关键概念以及如何最好地应用它们。
如果你刚刚起步,这些最佳实践不仅可以帮助你编写更好的代码,还可以帮助你更好地维护和扩展 Python 代码库或数据管道。
目录
- 为什么要拆分您的项目?
- 构建 Python 项目的 9 个最佳实践
- 演示:一个简单的数据工程项目
- 构建项目以便于协作
- Python 项目文件夹结构和密钥文件
二、为什么要拆分您的项目?
随着Python程序变得越来越大,它们变得越来越难以管理。如果团队正在项目上进行协作并同时对项目的多个方面进行更改,则尤其如此。
为了使项目更易于管理和维护,我们将大型、笨拙的编程任务分解为更易于管理的子任务或模块。顾名思义,模块可以在多个地方重用。
将项目分解为模块称为“模块化编程”。如前面的文章所述,函数、模块和包都是模块化编程中使用的机制。模块化编程提供了许多优点。
- 它允许您一次专注于一个模块来简化您的工作。
- 它使您的项目更易于维护。 如果团队正在共同处理一个项目,则采用模块化方法可以降低您的工作最终导致版本冲突的可能性。
- 它使您的代码更可重用。 如果你的项目是一个大型的单体,任何想要重用它的人都必须解析大量代码。如果代码按模块进行组织,则仅导入所需的部件会变得更容易。
- 它减少了重复。 根据上述观点,模块化代码更具可重用性,这意味着您最终复制函数的可能性较小。
- 它有助于避免命名空间冲突,因为每个模块都可以定义一个单独的命名空间。
三、构建 Python 项目的 9 个最佳实践
当你在网上寻找关于如何组织和编写Python代码的建议时,你会发现很多不同的想法。但实际上,它归结为一些基本的事情。
3.1. 组织代码
在处理项目时,正确组织代码至关重要。首先,您可以为项目的不同部分创建单独的文件夹,例如一个用于代码本身,一个用于数据,一个用于测试,一个用于文档。这将帮助您更快地找到所需的内容,并使其他人更容易浏览您的代码。
3.2. 使用一致的命名
在整个项目中为文件和文件夹使用一致的名称非常重要。尝试遵循约定,例如对变量和函数使用下划线,对类使用大写字母。这将使阅读和理解代码变得更加容易。
3.3. 使用版本控制
即使在单独工作时,使用像 Git 这样的工具来跟踪对代码的更改也是推荐的最佳做法。它允许您记录更改,并轻松地将工作备份到基于云的存储库。大多数基于云的 Git 解决方案都为独立从业者提供免费层。
3.4. 使用包管理器
使用像 pip 这样的包管理器来管理依赖项将帮助您安装和跟踪项目需要运行的所有不同软件。在处理具有许多依赖项的大型项目时,这一点尤其重要。
3.5. 创建虚拟环境
若要使项目与计算机上的其他项目隔离,可以使用虚拟环境。这将防止不同项目中使用的包之间的冲突。
3.6. 注释您的代码
添加注释来解释您的代码正在做什么以及如何使用它对于使您的代码更易于其他人访问非常重要。它还可以帮助您记住编写代码时的想法。
3.7. Test, test, test
Using automated tests to check that your code works as expected is essential for catching bugs early on. This will save you time and prevent issues down the line.
3.8. 绒毛和风格
使用 Ruff 或 Flake8 等工具来确保您的代码看起来一致并捕获常见错误将帮助您编写更好的代码。这些工具检查您的代码是否与官方 Python 风格指南 PEP 8 保持一致。还可以使用 Black 等工具来确保代码在整个项目中看起来相同。这将帮助您保持一致性,并使其更易于阅读和理解您的代码。
3.9. 打包分享
使用像setuptools这样的工具来打包和分发你的Python代码将更容易与他人分享你的工作。这也将有助于确保其他人可以使用你的代码而不会遇到任何问题。
四、演示:一个简单的数据工程项目
让我们将这些技巧应用于一个动手示例。我们将使用几种最佳做法,包括有组织的代码、一致的命名、有用的注释和测试。
我们将编写一个脚本来从数据库中提取数据,对其进行转换,然后将其加载到另一个数据库中。让我们首先在名为 my_module.py 的模块中定义变量和函数:
# Constants
SOURCE_DB = "source_db"
DESTINATION_DB = "destination_db"
TABLE_NAME = "table_name"
DATE_COLUMN = "date_column"
SALES_COLUMN = "sales_column"# Functions
def extract_data(table_name):# Code to extract data from the source databasedef transform_data(data_frame):# Code to transform the datadef load_data(data_frame):# Code to load the data into the destination database
在此示例中,我们对变量和函数使用一致的名称。像 、 、 和 等常量都大写并用下划线分隔。像 、 和 这样的函数都是小写的,用下划线分隔。SOURCE_DB
DESTINATION_DB
TABLE_NAME
DATE_COLUMN
SALES_COLUMN
extract_data
transform_data
load_data
接下来,让我们在文件中编写一个简单的单元测试,以确保我们的代码按照我们想要的方式工作:test.py
import unittest
import pandas as pd
from my_module import transform_dataclass TestDataTransformation(unittest.TestCase):def test_transform_data(self):# Create a sample input DataFrameinput_data = pd.DataFrame({"date_column": ["2022-01-01", "2022-02-01", "2022-03-01"],"sales_column": [100, 200, 300]})# Call the transform_data functionoutput_data = transform_data(input_data)# Check the output DataFrameexpected_output = pd.DataFrame({"year": [2022, 2022, 2022],"month": [1, 2, 3],"sales": [100, 200, 300]})pd.testing.assert_frame_equal(output_data, expected_output)
在这里,我们导入了 and 模块,以及来自unittest
pandas
transform_data
my_module.py.
然后,我们定义了一个名为的测试类,它继承自 .在此类中,我们定义了一个名为 的单个测试函数。此函数创建一个包含三行数据的示例输入数据帧,使用此输入数据调用该函数,然后检查输出数据帧以确保它具有预期值。TestDataTransformation
unittest.TestCase
test_transform_data
transform_data
我们使用相同的三行数据定义预期的输出数据帧,并使用该函数检查输出数据帧是否与预期的数据帧匹配。如果输出数据帧与预期数据帧匹配,则测试将通过。否则,测试将失败,并提供有关不匹配发生位置的信息。pd.testing.assert_frame_equal
五、构建项目以便于协作
与其他开发人员一起编写代码时,要考虑的最重要的事项是:
- 确保您拥有正确的代码版本,并且
- 正确的软件依赖项。
这就是版本控制派上用场的地方。假设一个开发团队正在开发一个涉及开发 Web 应用程序的 Python 项目。每个开发人员都在处理项目的特定功能或模块。如果没有版本控制,团队将不得不手动协调他们的工作,这可能令人生畏且容易出错。一个开发人员可能会意外地覆盖另一个开发人员的工作,从而导致进度丢失或冲突。
但是,通过使用 Git 等版本控制系统,团队可以轻松跟踪更改、协作处理代码,并确保每个人都使用相同版本的代码库。使用 Git,每个开发人员都可以在自己的分支上工作,这允许他们独立进行更改,而不会影响主代码库。
当需要集成每个人的更改时,Git 提供了用于合并代码和解决冲突的工具,使团队更容易协同工作。Git 还提供了代码库的完整历史记录,包括每个开发人员所做的所有更改,这对于调试和了解代码如何随时间演变非常有用。
为了确保对共享代码的更改不会破坏其他项目,最好使用 pytest 等自动化测试工具。在将代码更改合并到主代码库之前查看代码更改也是一种很好的做法。
最后,当涉及到“轻松协作”时,正如我们的最佳实践列表中提到的,在编写代码时记录代码非常重要。这使新团队成员更容易理解代码并加快速度。
六、Python 项目文件夹结构和密钥文件
您可能想知道为什么 Python 项目具有结构 .这种组织项目的方式在 Python 中很流行,因为它有助于保持一切整洁。顶部文件夹称为“my-project”,类似于整个项目的主文件夹。使用破折号和下划线有助于区分项目的两个级别。特别是,下划线有助于将项目引用与可能使用虚划线符号的变量或函数名称区分开来。因为破折号也是一个减号,所以定义 python 包的“内部级别”必须使用下划线。my-project/my_project
关于如何在“我的项目”中组织文件,有松散的规范。顶层通常包含一个文件和各种配置文件。项目中最重要的部分是它包含的一个或多个 python 包。python 包是一个目录,构成 Python 导入系统的有效目标,通常包含一个文件。在此示例中,有一个名为“my_project”的 Python 包,它位于顶层。README.md
__init__.py
从这里开始,在大多数项目中找到的关键文件和子文件夹是:
- 依赖项管理文件(通常为 或 )此文件用于配置项目及其依赖项。我们在本博客系列的第二部分中探讨了依赖关系管理。
setup.py
pyproject.toml
README.md
:此文件以 markdown 形式编写,简要介绍了您的项目、其用途以及任何安装或使用说明。LICENSE
:此纯文本文件指定发布代码的许可证。有许多开源许可证可供选择,因此请务必选择适合您需求的许可证。
此外,许多项目将具有以下两个文件夹:
src/
:此目录是 python 包的替代位置,如果您不想将它们直接放在项目根目录中。tests/
:此目录包含验证项目功能的测试代码。您可以使用 pytest 或 unittest 等测试框架来编写和运行测试。
接下来...
我们已经分享了随着项目复杂性的增加,以结构化的方式组织 Python 项目的重要性,特别是如果您是团队的一员或计划与其他开发人员共享您的工作。通过遵循本文中概述的最佳做法,可以更轻松地维护和缩放基本代码或数据管道。