前言模块是我们用来组织Python代码的基本单元。许多强大而复杂的站点都是由成百上千个独立的模块组成的。尽管模块是不可替代的,但它们有时也会给我们带来麻烦。例如,当你接手一个新项目时,你只是扩展项目目录。当你第一眼看到错综复杂、难以理解的模块结构时,你肯定会想:“这个项目太难了”。在这篇文章中,我准备了一个与模块相关的小故事分享给大家。关于模块的小故事小R是一名刚从学校毕业的计算机科学专业的学生。半个月前,他面试了一家互联网公司做Python开发,负责一个跟用户活跃度相关的小项目。该项目的主要功能是查询站点的活跃用户,并向他们发送有关活动积分的通知:“尊敬的用户,您好,您当前的活动积分是x”。项目主要由notify_users.py脚本和fancy_site包组成。各个文件的结构和内容如下:文件notify_users.py:文件fancy_site/users.py:文件:fancy_site/marketing.py:只需在项目目录下执行pythonnotify_user.py,即可向所有活跃用户发送通知.需求变了,但是有一天,产品经理上门说,给用户发内部消息通知不行,容易被用户忽略。除了站内信,我们还需要同时给用户推送一条短信通知。琢磨了五秒,小R对产品经理说:“这个需求可以做!”。毕竟给手机号码发短信的send_sms()函数已经写好了。他只需要先在add_notification方法中添加一个可选参数enable_sms=False,当传入值为True时调用fancy_site.marketing模块中的send_sms函数即可。听起来一点难度都没有。十分钟后,小R将user.py改成如下:然而,当他修改完代码,再次执行notify_users.py脚本时,程序报错:errormessageSay,cannotimportUserobjectfromfancy_site.usersmodule.解决循环依赖问题小R仔细分析错误,发现错误是由于用户和营销模块之间的循环依赖引起的。当程序在notify_users.py文件中导入fancy_site.users模块时,users模块发现自己从marketing模块中导入了send_sms函数。在加载marketing模块的过程中,解释器反过来发现需要依赖users模块中的User对象。这样一来,整个模块依赖就变成了一个环,程序自然就无法执行了。不过,没有问题会困扰可以正常访问Google的程序员。小R在网上随便搜了一下,发现这样的问题很好解决。因为Python的import语句非常灵活,他只需要将users模块中导入send_sms函数的语句移到add_notification方法中,延迟import语句的执行即可。更改一行代码后,您就完成了。简单测试后,小R发现一切正常,然后将代码推送上去。然而,就在小R还没来得及喜欢自己的时候,意想不到的事情发生了。这个看似近乎完美的代码更改在代码审查期间被审核员C拒绝了。小C的问题小C是小R的同事,是一名有多年经验的Python程序员。他对小R说:“使用延迟导入可以立即解决包导入问题。但是这个小问题的背后隐藏着更多的问题。信息。比如,你有没有想过send_sms这个函数不适合放在营销模块里了?”小C一问,聪明的小R立马意识到了问题。在users模块里面发短信,重点是不是用惰性导入来解决循环依赖,而是以此为契机,发现当前模块之间的不合理依赖,拆分/合并模块,创建新的层和抽象,最终消除循环依赖。在认清问题后,他很快提交了新的代码修改,在新代码中,他创建了一个专门用于通知和消息的工具模块msg_utils,然后将send_sms函数移入其中,之后users模块就可以毫不费力地从msg_utils模块导入send_sms函数.新的模块依赖如下图所示:在新的模块结构中,整个项目被整齐的分为三层,依赖模块之间的依赖关系也变成了单向流。之前在函数内部导入的“延迟导入”技术自然是没用了。小R修改后的代码得到了大家的认可,很快就被合并到了主分支中。故事已经结束了,那么这个故事告诉我们什么呢?总结模块之间的循环依赖是大型Python项目中非常普遍的问题,越复杂的项目越容易遇到这个问题。我们在参与这些项目的时候,如果对模块的结构、层次、抽象都缺乏应有的关注。然后项目很容易慢慢变得极其复杂且难以维护。因此,合理的模块结构和分层非常重要。可以大大减轻开发者的精神负担和项目维护成本。这就是为什么我要与您分享这个简单的故事。“在一个函数内延迟导入”没有错,但更要注意整个项目中的模块依赖和分层是否合理。最后,我们试着从小R的故事中强行总结出几个道理:合理的模块结构和分层可以降低项目开发和维护成本合理的模块结构不是一成不变的,应该随着项目的发展和遇到问题而调整“简单但有缺陷”的解决方案,但选择“麻烦但正确”的解决方案。整个项目中模块之间的依赖关系应该是单向的,不应该有循环依赖。附录来源:图片Unsplash上??RicardoGomezAngel的更多系列文章地址:https://github.com/piglei/one...系列其他文章:Python匠人:函数返回结果的技巧Python匠人:三好异常处理的习惯Python工匠:写正宗循环的两点建议蓝鲸智云本文由腾讯蓝鲸智云编辑发布。一站式自动化运维平台。目前已经推出社区版和企业版,欢迎体验。官网:https://bk.tencent.com/下载链接:https://bk.tencent.com/download/社区:https://bk.tencent.com/s-mart...
