一个关于Python模块的小故事

程序员向暗恋的女神鼓起勇气表白……但这结局猝不及防 导语 还有最后倒计时四天就是放假了,有想好跟对象去哪儿约会嘛~ 【列如:带回家—一场说走就走的浪漫旅行…打住,请小编赐我一个对象,啊哈哈哈哈~好兄弟的我.jpg】 你不会还单着吧?不会吧不会吧? 贴心如我!今天为大家送上几款表白/秀恩爱小代码~表白成功记得多点点赞哈,咳咳咳,要求不高! 今天带大家学习一下人类高质量男性/女性 都是怎么表白,节日浪漫约会的~ 啊这!搞错了再来—— 正确的情人节、七夕,恋爱节日,当然要来一束玫瑰更能显示你的心意满满啦~ 正文 我知道你们看到我前文长篇大论之后肯定会觉得今天小 阅读详情

模块(Module)是我们用来组织 Python 代码的基本单位。很多功能强大的复杂站点,都由成百上千个独立模块共同组成。

虽然模块有着不可替代的用处,但它有时也会给我们带来麻烦。比如,当你接手一个新项目后,刚展开项目目录。第一眼就看到了攀枝错节、难以理解的模块结构,那你肯定会想:“这项目也太难搞了。” ?

在这篇文章里,我准备了一个和模块有关的小故事与你分享。

一个关于模块的小故事

小 R 是一个刚从学校毕业的计算机专业学生。半个月前,他面试进了一家互联网公司做 Python 开发,负责一个与用户活动积分有关的小项目。项目的主要功能是查询站点活跃用户,并为他们发送有关活动积分的通知:“亲爱的用户,您好,您当前的活动积分为 x”。

项目主要由 notify_users.py 脚本和 fancy_site 包组成,结构与各文件内容如下:

├── fancy_site	
│   ├── __init__.py	
│   ├── marketing.py        # 与市场活动有关的内容	
│   └── users.py            # 与用户有关的内容	
└── notify_users.py     # 脚本:发送积分通知

文件 notify_users.py:

from fancy_site.users import list_active_users	
from fancy_site.marketing import query_user_points	
def main():	
    """获取所有的活跃用户,将积分情况发送给他们"""	
    users = get_active_users()	
    points = list_user_points(users)	
    for user in users:	
        user.add_notification(... ...)	
        #  <... 已省略 ...>

文件 fancy_site/users.py:

from typing import List	
class User:	
    # <... 已省略 ...>	
    def add_notification(self, message: str):	
        """为用户发送新通知"""	
        pass	
def list_active_users() -> List[User]:	
    """查询所有活跃用户"""	
    pass

文件:fancy_site/marketing.py:

from typing import List	
from .users import User	
def query_user_points(users: List[User]) -> List[int]:	
    """批量查询用户活动积分"""	
def send_sms(phone_number: str, message: str):	
    """为某手机号发送短信"""

只要在项目目录下执行 python notify_user.py,就能实现给所有活跃用户发送通知。

需求变更

但有一天,产品经理找过来说,光给用户发站内信通知还不够,容易被用户忽略。除了站内信以外,我们还需要同时给用户推送一条短信通知。

琢磨了五秒钟后,小 R 跟产品经理说:“这个需求可以做!”。毕竟给手机号发送短信的 send_sms() 函数早就已经有人写好了。他只要先给 add_notification 方法添加一个可选参数 enable_sms=False,当传值为 True时调用 fancy_site.marketing 模块里的 send_sms 函数就行。

一切听上去根本没有什么难度可言,十分钟后,小 R 就把 user.py 改成了下面这样:

# 导入 send_sms 模块的发送短信函数	
from .marketing import send_sms	
class User:	
    # <...> 相关初始化代码已省略	
    def add_notification(self, message: str, enable_sms=False):	
        """为用户添加新通知"""	
        if enable_sms:	
            send_sms(user.mobile_number, ... ...)

但是,当他修改完代码,再次执行 notify_users.py 脚本时,程序却报错了:

Traceback (most recent call last):	
  File "notify_users.py", line 2, in <module>	
    from fancy_site.users import list_active_users	
  File .../fancy_site/users.py", line 3, in <module>	
    from .marketing import send_sms	
  File ".../fancy_site/marketing.py", line 3, in <module>	
    from .users import User	
ImportError: cannot import name 'User' from 'fancy_site.users' (.../fancy_site/users.py)

错误信息说,无法从 fancy_site.users 模块导入 User 对象。

解决环形依赖问题

小 R 仔细分析了一下错误,发现错误是因为 users 与 marketing 模块之间产生的环形依赖关系导致的。

当程序在 notify_users.py 文件导入 fancy_site.users 模块时, users 模块发现自己需要从 marketing 模块那里导入 send_sms 函数。而解释器在加载 marketing 模块的过程中,又反过来发现自己需要依赖 users 模块里面的 User 对象。

如此一来,整个模块依赖关系成为了环状,程序自然也就没法执行下去了。

640?wx_fmt=png

不过,没有什么问题能够难倒一个可以正常访问 Google 的程序员。小 R 随便上网一搜,发现这样的问题很好解决。因为 Python 的 import 语句非常灵活,他只需要 把在 users 模块内导入 send_sms 函数的语句挪到 add_notification 方法内,延缓 import 语句的执行就行啦。

class User:	
    # <...> 相关初始化代码已省略	
    def add_notification(self, message: str, send_sms=False):	
        """为用户添加新通知"""	
        # 延缓 import 语句执行	
        from .marketing import send_sms

改动一行代码后,大功告成。小 R 简单测试后,发现一切正常,然后把代码推送了上去。不过小 R 还没来得及为自己点个赞,意料之外的事情发生了。

这段明明几乎完美的代码改动在 Code Review 的时候被审计人小 C 拒绝了。

小 C 的疑问

小 R 的同事小 C 是一名有着多年经验的 Python 程序员,他对小 R 说:“使用延迟 import,虽然可以马上解决包导入问题。但这个小问题背后隐藏了更多的信息。比如,你有没有想过 send_sms 函数,是不是已经不适合放在 marketing 模块里了?”

被小 C 这么一问,聪明的小 R 马上意识到了问题所在。要在 users 模块内发送短信,重点不在于用延迟导入解决环形依赖。而是要以此为契机,发现当前模块间依赖关系的不合理,拆分/合并模块,创建新的分层与抽象,最终消除环形依赖。

认识清楚问题后,他很快提交了新的代码修改。在新代码中,他创建了一个专门负责通知与消息类的工具模块 msg_utils,然后把 send_sms 函数挪到了里面。之后 users 模块内就可以毫无困难的从 msg_utils 模块中导入 send_sms 函数了。

from .msg_utils import send_sms

新的模块依赖关系如下图所示:

640?wx_fmt=png

在新的模块结构中,整个项目被整齐的分为三层,模块间的依赖关系也变得只有单向流动。之前在函数内部 import 的“延迟导入”技巧,自然也就没有用武之地了。

小 R 修改后的代码获得了大家的认可,很快就被合并到了主分支。故事暂告一段落,那么这个故事告诉了我们什么道理呢?

总结

模块间的循环依赖是一个在大型 Python 项目中很常见的问题,越复杂的项目越容易碰到这个问题。当我们在参与这些项目时,如果对模块结构、分层、抽象缺少应有的重视。那么项目很容易就会慢慢变得复杂无比、难以维护。

所以,合理的模块结构与分层非常重要。它可以大大降低开发人员的心智负担和项目维护成本。这也是我为什么要和你分享这个简单故事的原因。“在函数内延迟 import” 的做法当然没有错,但我们更应该关注的是:整个项目内的模块依赖关系与分层是否合理。

最后,让我们再尝试从 小 R 的故事里强行总结出几个道理吧:

  • 合理的模块结构与分层可以降低项目的开发维护成本

  • 合理的模块结构不是一成不变的,应该随着项目发展调整

  • 遇到问题时,不要选“简单但有缺陷”的那个方案,要选“麻烦但正确”的那个

  • 整个项目内的模块间依赖关系流向,应该是单向的,不能有环形依赖存在


另外我们千人的Python星球福利,倒计时最后一天,错过再等一年!

千人Python知识星球重大福利,一年仅一次!

一则小故事带你弄清Python装饰器 Python装饰器,面向切面编程。 阅读详情

相关推荐

SAP IDOC实战:5分钟搞定采购订单自动生成销售订单(附完整配置流程)

本文详细介绍了如何利用SAP IDOC技术,在5分钟内实现采购订单自动生成销售订单的完整配置流程。通过清晰的步骤解析和实战案例,帮助用户理解IDOC在跨公司交易中的核心价值,掌握从环境准备、合作伙伴参数配置到输出类型设置的关键操作,并提供了常见错误的排查方法,助力企业快速搭建高效、可靠的供应链自动化桥梁。

dd012的博客 940

Python工匠 | 全书要点汇总

对各章的总结汇总在了一起,全文6000余字。

成长之路 1090

LBM模式学习·保姆级安装及初步使用教程

在学习LBM的过程中,我感觉可供参考的材料较为有限,对于一个独立学习LBM模式的初学者非常不友好(我就是这个初学者哈哈),因此萌生了写一篇保姆级的LBM模式教程,并将我踩过的坑一一指出,有助于后来者更快地上手该模式,而非半途而废。

weixin_42762673的博客 1万+

python工匠:案例、技巧合工程实践学习小结

这一点和C语言有点不一样,总是把变量声明放在最前面。python变量本身可读性稍差。变量定义移动到每段“各司其职”的代码头部,大大缩短了变量从初始化到被使用的“距离”。当读者阅读代码时,可以更容易理解代码的逻辑,而不是来回翻阅代码。函数不宜过长,超过200行需要进行功能拆分/切割将复杂的表达式赋值为一个临时变量,代码更易读。把不必要的东西赋值为临时变量,反而会让代码显得啰唆,删掉赘语的句子,变得更精练、更易读。

weixin_43099454的博客 770

从零到一:用STM32 FOC算法驯服无刷电机的艺术

本文详细介绍了如何使用STM32和FOC算法实现无刷电机的高性能控制。从硬件搭建、参数识别到闭环调节,一步步解析FOC算法的核心原理与调优技巧,帮助开发者掌握电机控制的关键技术,实现从零到一的精准驯服。

kkk56的博客 920

Java分布式流处理,flink+kafka实现电商网站个性化商品推荐系统

在现代电商环境中,用户每天都会浏览大量商品页面,而这些行为数据中蕴藏着丰富的信息。通过分析用户的浏览历史、购买记录以及对特定商品的兴趣程度,我们可以为用户提供更加个性化的商品推荐,从而提升用户体验和转化率。为了实现实时的个性化推荐,我们需要构建一个能够快速处理并响应用户行为变化的数据处理管道。

横竖撇折点 2144

Python开发必看书籍:《Python工匠》

python相关的就业方向很多,学校开设的python课程大多集中在数据分析和数据挖掘领域。然而实际工作中,算法工程师完成模型算法之后,往往还需要负责接口的开发上线。偏工程的数据治理方向偏业务的数据分析方向偏算法的数据挖掘方向偏开发的数据开发方向偏产品的数据产品经理我在入职两年的时候负责了一个大项目的开发工作,设计了5个功能模块,接入了1个查询接口2个数据库7个预测模型,一整套弄下来非常的struggle。Python开发远比我预期的难度要大。

2401_84205765的博客 1835

指纹浏览器指纹工厂(下):基于真实设备数据特征的马尔可夫链生成与校验

本文揭示了静态指纹生成算法在高级风控时序追踪下的致命缺陷,指出违背设备演进马尔可夫性质(如无状态跳跃、因果断裂)是导致指纹存活率骤降的核心原因。通过分析风控系统的时序状态机与多维特征验证机制,提出基于隐马尔可夫模型(HMM)的动态指纹架构:以真实设备的状态转移链为蓝本,构建异步演进的“数字基因熔炉”,通过非均匀时间步长、突发事件响应及微观因果绑定,模拟软硬件独立更新的物理法则。最终实现指纹在时间维度与微观特征上的自洽,规避风控的时序陷阱。

数据知道的博客 418

python故事_Python背后的故事!

Hello,大家好,相信关注一点君的小伙伴们对Python应该有了一点了解,今天就再带着大家一起来看看Python语言背后的故事吧。昨天我们认识了Python之父这个阔爱的胖纸,就从他开始聊起吧!1.Python的起源先从Python的起源说起吧,1982年,Guido从阿姆斯特丹大学获得了数学和计算机硕士学位。然而,尽管他算得上是一位数学家,但他更加享受计算机带来的乐趣。用他的话说,尽管拥有数学...

weixin_39638086的博客 1243

在 ABAP 平台上搭建 OAuth 2.0 Server:架构、流程、权限与落地实战

摘要:本文为SAP ABAP开发人员提供将ABAP平台配置为OAuth 2.0授权服务器的实战指南。重点介绍两种授权流程(授权码和SAML Bearer)的实现方案,包括核心事务配置(SOAUTH2/SAML2)、授权对象(S_SCOPE)管理以及端点交互规范。通过具体配置清单和三类典型集成场景(第三方Web应用访问OData、企业集成平台调用、BTP应用对接)的落地示例,帮助读者快速构建安全的OAuth 2.0服务架构。文档强调SSL/TLS基础安全、scope最小授权原则以及授权与令牌端点的标准交互模式

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 312

KEPServerEX 6 之 GE Ethernet 连接FANUC ROBOT机器人实战

GE Fanuc是GE公司控制系统部门的一部分,成立于1998年。其主要业务涵盖工业自动化、控制系统、PLC和组态软件等领域。其产品可用于包括自动化、过程自动化、国防、汽车制造、通讯、医疗和航空航天等各种工业领域2009 8月 GE和FANUC今天宣布两家公司已同意解除合资企业GE FANUC自动化公司。通过以上历史,GE Ethernet Driver 当下还支持对接FANUC ROBOT机器人 就不奇怪了。

-雲飛兄-博客 1795

《Python工匠》学习笔记----第二章:数值与字符串

《Python工匠》学习笔记

m0_48069960的博客 553

英飞凌 AURIX TC3XX 系列单片机的链接文件

这篇介绍英飞凌 AURIX TC3XX 系列单片机的链接文件,主要是针对使用 SOTA 功能如何修改链接文件,完整地实现 SOTA 功能

大橙子的博客 4385

python模块_一个关于Python模块的小故事

模块(Module)是我们用来组织 Python 代码的基本单位。很多功能强大的复杂站点,都由成百上千个独立模块共同组成。虽然模块有着不可替代的用处,但它有时也会给我们带来麻烦。比如,当你接手一个新项目后,刚展开项目目录。第一眼就看到了攀枝错节、难以理解的模块结构,那你肯定会想:“这项目也太难搞了。” ????在这篇文章里,我准备了一个和模块有关的小故事与你分享。一个关于模块的小故事小 R 是...

weixin_39788386的博客 210

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

python模块大全_一个关于模块的小故事 | Python 工匠

文 | piglei 编辑 | EarlGrey 推荐 | 编程派微信公众号(ID:codingpy)前言模块(Module)是我们用来组织 Python 代码的基本单位。很多功能强大的复杂站点,都由成百上千个独立模块共同组成。虽然模块有着不可替代的用处,但它有时也会给我们带来麻烦。比如,当你接手一个新项目后,刚展开项目目录。第一眼就看到了攀枝错节、难以理解的模块结构,那你肯定会想: “...

weixin_39567013的博客 114

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

py文件 添加模块映射_一个关于模块的小故事 | Python 工匠

文 | piglei 编辑 | EarlGrey 推荐 | 编程派微信公众号(ID:codingpy)前言模块(Module)是我们用来组织 Python 代码的基本单位。很多功能强大的复杂站点,都由成百上千个独立模块共同组成。虽然模块有着不可替代的用处,但它有时也会给我们带来麻烦。比如,当你接手一个新项目后,刚展开项目目录。第一眼就看到了攀枝错节、难以理解的模块结构,那你肯定会想: “这项目也太...

weixin_35006181的博客 131

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

python发明小故事_Python 工匠:一个关于模块的小故事

前言这是 “Python 工匠”系列的第 9 篇文章。[查看系列所有文章]模块(Module)是我们用来组织 Python 代码的基本单位。很多功能强大的复杂站点,都由成百上千个独立模块共同组成。虽然模块有着不可替代的用处,但它有时也会给我们带来麻烦。比如,当你接手一个新项目后,刚展开项目目录。第一眼就看到了攀枝错节、难以理解的模块结构,那你肯定会想:“这项目也太难搞了。”:joy:在这篇文...

weixin_39883906的博客 168

Python 工匠:一个关于模块的小故事

Python 工匠系列又来了,今天分享的是一个关于 Python 模块的小故事。模块(Module)是我们用来组织 Python 代码的基本单位。很多功能强大的复杂站点,...

静觅 297

python发明小故事简写_一个关于模块的小故事 | Python 工匠

原标题:一个关于模块的小故事 | Python 工匠 文 | piglei 编辑 | EarlGrey推荐 | 编程派微信公众号(ID:codingpy)前言模块(Module)是我们用来组织 Python 代码的基本单位。很多功能强大的复杂站点,都由成百上千个独立模块共同组成。虽然模块有着不可替代的用处,但它有时也会给我们带来麻烦。比如,当你接手一个新项目后,刚展开项目目录。第一眼就看到了攀枝错...

weixin_39758392的博客 151

9-Python 工匠:一个关于模块的小故事

模块间的循环依赖是一个在大型 Python 项目中很常见的问题,越复杂的项目越容易碰到这个问题。当我们在参与这些项目时,如果对模块结构、分层、抽象缺少应有的重视。那么项目很容易就会慢慢变得复杂无比、难以维护。所以,合理的模块结构与分层非常重要。它可以大大降低开发人员的心智负担和项目维护成本。这也是我为什么要和你分享这个简单故事的原因。整个项目内的模块依赖关系与分层是否合理。合理的模块结构与分层可以降低项目的开发维护成本合理的模块结构不是一成不变的,应该随着项目发展调整。

wujianyouhun的专栏 888

Python爬虫之定时给TA发送微信消息(十七)

对朋友很久没联系 不是因为感情变了 而是因为生活变了 毕竟年龄增长了 肩负的责任重了 身边的牵挂多了…… 何不如,写一个程序,每天都给TA发送,TA喜欢的、或者是你想对TA说的话。今天,就利用Python中的wxpy模块,将你想说的话发给TA吧!!!!!!!!!!!!!!!!

Blessy_Zhu的博客 1万+

利用 pycharm 网络爬虫 定时给你的TA发送睡前小故事

每天自动给你的那个TA发送一个小故事,是不是很浪漫啊? 让我们一起来实现吧! 首先,找个目标,诶,巧了,我这里有一个:http://www.tom61.com/ertongwenxue/shuiqiangushi/ 既然目标有了,那就 盘他!(盘他前要去该网站“踩个点”) 踩点完毕就开始吧############################### 1.导入必要的模块 import smtpli...

jiabaoyu0001的博客 579

python实操小案例

初学python入门,写一写,还望各位同道之人指教

hjg1116的博客 2084

python网络爬虫的学习

在上一篇博客我已经将python高级摘要的笔记分享完毕了,从这一篇博客开始写python网络爬虫的笔记。

xxt201的博客 367

定时发送睡前小故事——python

原文:https://blog.youkuaiyun.com/lyc44813418/article/details/88583021 # -*- coding: utf-8 -*- import requests from bs4 import BeautifulSoup import smtplib from email.mime.text import MIMEText import ran...

weixin_41340063的博客 297

(开题)flask框架古文小故事分享网站(程序+论文+python)

古文小故事,作为中华传统文化的重要组成部分,以其独特的魅力和深邃的内涵,千百年来一直深受人们的喜爱。这些故事不仅蕴含着丰富的历史信息和文化价值,还传递着先人的智慧和道德观念。然而,在数字化时代,古文小故事的传播方式相对单一,主要依赖于书籍、课堂等传统媒介,难以满足现代人多样化、便捷化的阅读需求。因此,本研究拟开发一个古文小故事分享网站,旨在利用互联网技术的优势,拓宽古文小故事的传播渠道,让更多人能够轻松接触、阅读和分享这些经典故事。

sheji713的博客 1427
上一篇: 互联网大佬学历,背景大揭秘,看看是你的老乡还是校友
下一篇: 谁说学Python不实用,看我如何用数据分析来反击给我丢锅的同事!
菜鸟学Python
博客等级 码龄9年 8083粉丝 571原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值