当前位置: 首页 > 后端技术 > Python

如何搭建一个完美的Python项目?

时间:2023-03-26 17:29:37 Python

当开始一个新的Python项目时,很容易直接进入并开始编码。事实上,花一点时间选择一个优秀的库将在未来的开发中节省大量时间,并带来更愉快的编码体验。在一个理想的世界里,所有的开发者关系都是相互依赖和联系的(协同开发),代码格式完美,没有低级错误,测试覆盖所有代码。另外,所有这些都将在每次提交时得到保证。(统一代码风格、类型检测、高测试覆盖率、自动检测)在这篇文章中,我将介绍如何构建一个可以做到这几点的项目。您可以按照这些步骤操作,或者直接跳到使用cookiecutter生成项目部分(老手)。首先我们新建一个工程目录:mkdirbest_practicescdbest_practicespipx安装Python第三方库的命令行工具Pipx[2]是一个可以用来快速安装Python第三方库的命令行工具。我们将使用它来安装pipenv和cookiecutter。使用以下命令安装pipx:python3-mpipinstall--userpipxpython3-mpipxensurepath使用pipenv进行依赖管理Pipenv[3]自动为您的项目创建和管理virtualenv(虚拟环境),并安装/卸载包添加/从Pipfile中删除包。它还会生成非常重要的Pipfile.lock以确保可靠性。知道您和您的队友使用相同的库版本会大大增加编程的信心和乐趣。Pipenv解决了使用同一个库不同版本的问题。Pipenv在过去的一段时间里得到了广泛的关注和认可,大家可以放心使用。安装命令如下:pipxinstallpipenvusesblackandisortforcodeformattingblack[4]可以格式化我们的代码:Black是一个不折不扣的Python代码格式化库。通过使用它,您可以放弃手动格式化代码的细节。作为回报,Black带来了速度、确定性和调整Python代码风格的痛苦,让您可以专注于更重要的事情。无论您正在阅读哪种项目,黑色格式的代码看起来都是一样的。一段时间后,格式不再是问题,因此您可以更专注于内容。黑色通过减少代码的方差使代码检查更快。isort[5]对我们的导入部分进行排序:isort对您导入的Python包部分(导入)进行排序,因此您不必再手动对导入进行排序。它可以按字母顺序对导入进行排序,并自动将它们分成几部分。使用pipenv安装它,这样它们就不会弄乱部署(你可以指定只在开发中安装):pipenvinstallblackisort--devBlack和isort是不兼容的默认选项,所以我们会让isort遵循黑色的原则.创建setup.cfg文件,添加如下配置:[isort]multi_line_output=3include_trailing_comma=Trueforce_grid_wrap=0use_parentheses=Trueline_length=88我们可以通过以下命令运行这些工具:pipenvrunblackpipenvrunisort使用flake8保证代码风格Flake8保证代码遵循PEP8定义的标准Python编码约定。使用pipenv安装:pipenvinstallflake8--dev和isort一样,它需要一些配置才能与black一起使用。将这些配置添加到setup.cfg:[flake8]ignore=E203,E266,E501,W503max-line-length=88max-complexity=18select=B,C,E,F,W,T4现在我们可以运行flake8,命令:pipenv运行flake8。使用mypy进行静态类型检查Mypy[6]是一个可选的Python静态类型检查器,旨在结合动态(或“鸭子”)类型和静态类型的优点。Mypy将Python的表现力和便利性与强大类型系统的编译时类型检查相结合,在任何PythonVM上运行它们,基本上没有运行时开销。在Python中使用类型需要一点时间来适应,但好处是巨大的。如下:Statictypingcanmakeprogramseasiertounderstandandmaintainstatictypingcanhelpyouearlierfindbugsandspendlesstimetestinganddebugsstatictypingcanhelpyoufindhard-to-findbugsbeforeyourcodegoesintoproductionpipenvinstallmypy--dev默认情况下,Mypy会递归检查所有导入包的类型注解,当库不包含这些注解时会报错。我们需要将mypy配置为仅在我们的代码上运行,并忽略没有类型注释的导入错误。我们假设我们的代码位于以下配置的best_practices包中。将其添加到setup.cfg中:[mypy]files=best_practices,testignore_missing_imports=true现在我们可以运行mypy:pipenvrunmypy这是一个有用的备忘单[7]。使用pytest和pytest-cov进行测试使用pytest[8]编写测试非常容易,消除编写测试的摩擦意味着可以快速编写更多测试!pipenvinstallpytestpytest-cov--dev这是一个来自pytest网站的简单例子:#contentoftest_sample.pydefinc(x):returnx+1deftest_answer():assertinc(3)==5执行它:$pipenvrunpytest===========================测试会话开始============================平台linux--Python3.x.y,pytest-5.x.y,py-1.x.y,pluggy-0.x.ycachedir:$PYTHON_PREFIX/.pytest_cacherootdir:$REGENDOC_TMPDIRcollected1itemtest_sample.pyF[100%]===================================失败=====================================________________________________________________________________________________deftest_answer():>assertinc(3)==5Eassert4==5E+where4=inc(3)test_sample.py:6:AssertionError===========================1在0.12秒内失败==========================我们所有的测试代码都放在test目录下,所以请在setup.cfg中添加这个目录:[tool:pytest]testpaths=test如果您还想查看测试覆盖率,请创建一个新文件.coveragerc,指定仅返回我们项目代码的覆盖率统计信息。例如,示例best_practices项目设置如下:[run]source=best_practices[report]exclude_lines=#Havetore-enablethestandardpragmapragma:nocover#Don’tcomplainaboutmissingdebug-onlycode:def__repr__ifself\.debug#如果测试没有命中防御性断言代码,不要抱怨:raiseAssertionErrorraiseNotImplementedError#如果不可运行的代码没有运行,不要抱怨:if0:if__name__==.__main__.:现在,我们可以运行测试并查看覆盖率。pipenvrunpytest--cov--cov-fail-under=100--cov-fail-under=100是设置项目的测试覆盖率。如果低于100%,则视为失败。用于预提交的Git钩子Git钩子允许您在任何时候想要提交或推送时运行脚本。这使我们能够在每次提交/推送时自动运行所有检测和测试。pre-commit[9]使得配置这些钩子变得容易。Git挂钩脚本对于在提交代码审查之前识别简单问题很有用。我们将在每次提交时运行挂钩,以自动指出代码中的问题,例如缺少分号、尾随空格和调试语句。通过在代码审查之前指出这些问题,代码审查者可以专注于更改的代码内容,而不会浪费时间处理这些琐碎的样式问题。在这里,我们将上述所有工具配置为在提交Python代码更改(gitcommit)时执行,然后仅在推送时运行pytest覆盖率(因为测试是最后一步)。创建一个新文件.pre-commit-config.yaml,配置如下:repos:-repo:localhooks:-id:isortname:isortstages:[commit]language:systementry:pipenvrunisorttypes:[python]-id:black名称:black阶段:[commit]语言:系统条目:pipenvrunblack类型:[python]-id:flake8名称:flake8阶段:[commit]语言:系统条目:pipenvrunflake8类型:[python]exclude:setup.py-id:mypyname:mypystages:[commit]language:systementry:pipenvrunmypytypes:[python]pass_filenames:false-id:pytestname:pyteststages:[commit]language:systementry:pipenv运行pytesttypes:[python]-id:pytest-covname:pyteststages:[push]language:systementry:pipenvrunpytest--cov--cov-fail-under=100types:[python]pass_filenames:false如果你需要跳过这些钩子,你可以运行gitcommit--no-verify或gitpush--no-verify使用cookiecutter来生成项目现在,我们已经知道包含了什么理想的项目,我们可以将其转换为模板[10],以便可以使用单个命令生成包含这些库和配置的新项目:pipxruncookiecuttergh:sourcery-ai/python-best-practices-cookiecutterFill在项目名称和仓库名称中,并把Generateanewprojectforyoutocompletethesesteps:#进入项目目录cd#初始化gitrepogitinit#安装依赖pipenvinstall--dev#Setuppre-commitandpre-pushhookspipenvrunpre-commitinstall-tpre-commitpipenvrunpre-commitinstall-tpre-push该模板项目包含一个非常简单的Python文件和测试以试用上述工具。写完代码感觉没问题,就可以执行第一次gitcommit,所有的hooks都会跑起来。集成到编辑器中虽然知道项目的代码在commit的时候总是处于最高层还是很兴奋的。但是修改完所有代码(提交时)才发现有问题,还是会很烦。所以实时暴露问题会好很多。保存文件时,请花一些时间确保代码编辑器运行这些命令。有即时反馈,这意味着您可以在代码仍然存在时快速修复引入的任何小问题。我个人使用一些很棒的Vim插件来完成这个任务:ale[11]runsflake8liveandrunsblack,isortandmypyonfilesave[12]vim-test[13]runspytestonfilesave以上是所有分享的内容时间。想了解更多python知识,请前往公众号:Python编程学习圈,发“J”免费领取,每日干货分享