当前位置: 首页 > news >正文

Python 函数、模块、包与项目结构,从重复代码到可维护小项目

写 Python 的前几天,所有代码放在一个文件里完全没问题。

但很快你会遇到两个问题。

第一,重复代码越来越多。比如计算总价、校验输入、读取文件,这些逻辑到处复制。

第二,文件越来越长。几百行代码堆在一起,想找一个函数都费劲。

函数、模块、包和项目结构,就是为了解决这两个问题。

它们是一条线:

重复代码

函数

多个函数放进模块

多个模块组成包

形成清晰项目结构

函数解决重复代码

不用函数时:

price=19.9count=3total=price*countprint(total)price=9.9count=5total=price*countprint(total)

同样的计算逻辑写了两遍。

用函数:

defcalc_total(price:float,count:int)->float:"""计算商品总价。"""returnprice*countprint(calc_total(19.9,3))print(calc_total(9.9,5))

函数的价值不是少写几行代码,而是把一段逻辑集中管理。

函数的输入和输出

函数最重要的是想清楚输入和输出。

defcalc_bmi(height:float,weight:float)->float:"""计算 BMI,height 单位为米,weight 单位为千克。"""returnweight/(height*height)bmi=calc_bmi(1.75,70)print(f"BMI:{bmi:.2f}")

输入是身高和体重。

输出是 BMI。

如果一个函数说不清输入输出,就很可能设计得不清楚。

printreturn不一样

defadd(a,b):print(a+b)result=add(10,20)print(result)

这段会先打印30,再打印None

原因是函数没有返回值。

正确写法:

defadd(a,b):returna+b result=add(10,20)print(result)

判断标准:

如果结果只是给人看,用print()

如果结果还要给后续代码使用,用return

参数的几种写法

位置参数:

defintroduce(name,age):returnf"我叫{name},今年{age}岁"print(introduce("小明",18))

关键字参数:

print(introduce(age=18,name="小明"))

默认参数:

defgreet(name,prefix="你好"):returnf"{prefix}{name}"print(greet("小明"))print(greet("小红","早上好"))

默认参数要小心可变对象。

不要这样写:

defadd_item(item,items=[]):items.append(item)returnitems

因为默认列表会被多次调用共享。

更安全:

defadd_item(item,items=None):ifitemsisNone:items=[]items.append(item)returnitems

作用域,变量在哪里有效

函数内部定义的变量,默认只在函数内部有效。

defsay_hello():message="你好"print(message)say_hello()# print(message) 这里会报错

函数外面的变量叫全局变量。

course="Python"defprint_course():print(course)print_course()

能读全局变量,不代表应该大量依赖全局变量。

函数最好通过参数接收数据,通过返回值交出结果。这样函数更独立,也更容易测试。

函数拆分原则

一个函数最好只做一件清楚的事。

比如订单处理,可以拆成:

defcalc_discount(amount:float)->float:ifamount>=200:returnamount*0.8ifamount>=100:returnamount-20returnamountdefprint_order(amount:float)->None:final_amount=calc_discount(amount)print(f"应付金额:{final_amount:.2f}")print_order(268)

calc_discount()只负责计算。

print_order()只负责展示。

职责拆开后,后面要改优惠规则,不会影响展示逻辑。

Docstring 怎么写才有价值

Docstring 不是给显而易见的代码写废话。

不推荐:

defadd(a,b):"""把 a 和 b 相加。"""returna+b

这个注释没有提供新信息。

更有价值:

defcalc_discount(price:float,discount:float)->float:"""计算折后价格,discount 取值范围为 0 到 1。"""returnprice*discount

这里说明了discount的取值范围,这个信息单看代码不一定知道。

一个.py文件就是一个模块

当函数越来越多,就应该拆文件。

项目结构:

project ├── main.py └── price_utils.py

price_utils.py

defcalc_discount(amount:float)->float:ifamount>=200:returnamount*0.8ifamount>=100:returnamount-20returnamount

main.py

fromprice_utilsimportcalc_discount amount=268final_amount=calc_discount(amount)print(f"应付金额:{final_amount:.2f}")

price_utils.py就是模块。

导入方式怎么选

导入整个模块:

importmathprint(math.sqrt(16))

从模块导入指定函数:

frommathimportsqrtprint(sqrt(16))

起别名:

importpandasaspd

不推荐初学者随便写:

frommathimport*

因为它会把很多名字直接放进当前文件,容易冲突,也不容易看出函数来源。

__name__和程序入口

很多文件底部会写:

defmain():print("程序开始")if__name__=="__main__":main()

意思是:

只有当前文件被直接运行时,才执行main()

如果这个文件被别的模块导入,不会自动执行。

这能避免导入模块时顺手执行一堆测试代码。

包是什么

多个模块可以放进一个文件夹,这个文件夹就可以作为包。

book_project ├── main.py └── utils ├── __init__.py ├── file_utils.py └── price_utils.py

导入:

fromutils.price_utilsimportcalc_discount

传统 Python 包里常见__init__.py。它可以为空,也可以控制包导出内容。

__pycache__是什么

运行 Python 项目后,你可能看到:

__pycache__

这是 Python 生成的字节码缓存目录,用来加快模块加载。

它不是你手写的源码,一般不用管。

如果后面使用 Git 管理代码,通常会把__pycache__加进忽略文件。

虚拟环境和 pip

项目开始用第三方库后,就需要虚拟环境。

创建:

python-mvenv .venv

Windows 激活:

.venv\Scripts\activate

安装依赖:

pipinstallrequests

导出依赖:

pip freeze>requirements.txt

别人拿到项目后安装:

pipinstall-rrequirements.txt

虚拟环境的意义是让每个项目有自己的依赖,避免项目之间互相污染。

一个推荐的小项目结构

python-study-project ├── main.py ├── requirements.txt ├── data │ └── books.json ├── services │ ├── __init__.py │ └── book_service.py └── utils ├── __init__.py └── file_utils.py

main.py放入口逻辑。

data放数据文件。

services放业务逻辑。

utils放通用工具函数。

项目结构不是越复杂越好。小项目从简单开始,随着代码变多再拆。

常见错误

文件名和标准库重名

不要把文件命名为:

json.py csv.py math.py random.py

这些名字和标准库冲突,可能导致导入异常。

循环导入

A 导入 B,B 又导入 A,可能出现循环导入。

解决方法通常不是硬改导入语句,而是重新拆职责,把共同依赖的内容放到第三个模块。

在模块顶层写太多执行代码

模块被导入时,顶层代码会执行。

测试代码放进:

if__name__=="__main__":...

当前目录不对导致导入失败

建议始终在项目根目录运行入口文件。

不要一会儿在子目录运行,一会儿在根目录运行,否则导入路径会变得难查。

练习,拆一个价格计算项目

创建结构:

price_project ├── main.py └── price_utils.py

price_utils.py

defcalc_discount(amount:float)->float:"""根据订单金额计算优惠后价格。"""ifamount>=200:returnamount*0.8ifamount>=100:returnamount-20returnamount

main.py

fromprice_utilsimportcalc_discount amount=float(input("请输入订单金额:"))final_amount=calc_discount(amount)print(f"应付金额:{final_amount:.2f}")

运行:

python main.py

如果能跑通,说明你已经从单文件脚本走到了最小项目结构。

参考资料

  • Python 官方函数教程:https://docs.python.org/3/tutorial/controlflow.html#defining-functions
  • Python 官方模块教程:https://docs.python.org/3/tutorial/modules.html
  • Python 虚拟环境教程:https://docs.python.org/3/tutorial/venv.html
  • PEP 8:https://peps.python.org/pep-0008/
http://www.jsqmd.com/news/1028422/

相关文章:

  • 南宁市黄金回收店铺排行榜及电话地址推荐 2026实测五家诚信优选实体门店 - 大熊猫898989
  • 宝鸡市2026年实测黄金回收五家店铺排行榜及电话地址推荐白银+铂金+彩金回收 - 盛世金银回收
  • AI Agent必须嵌入人类监督的四大刚性架构层
  • 终极yuzu模拟器下载指南:如何快速获取最新版本
  • 眉山市2026年实测黄金回收五家店铺排行榜及电话地址推荐白银+铂金+彩金回收 - 盛世金银回收
  • 保定市2026年实测黄金回收五家店铺排行榜及电话地址推荐白银+铂金+彩金回收 - 盛世金银回收
  • 2026年分析上海海峰梦再生资源的环保成效,哪家性价比高 - mypinpai
  • 2026年功能完善的政府采购平台口碑好、哪家性价比高,推荐这10家 - mypinpai
  • Qwen3.5-27B蒸馏版实测:推理提速22%的结构化思维优化实践
  • 计算机毕业设计之图书借阅管理系统的设计与实现
  • 贵港市2026年实测黄金回收五家店铺排行榜及电话地址推荐白银+铂金+彩金回收 - 盛世金银回收
  • AI编程工具使用方法横向评测:2026年工程师的决策系统构建指南
  • 手机号码定位查询终极指南:3分钟学会免费获取地理位置信息
  • 多维聚合中的数据变形术:维度层级、度量规则与安全计算
  • 保山市2026年实测黄金回收五家店铺排行榜及电话地址推荐白银+铂金+彩金回收 - 盛世金银回收
  • 贵阳市2026年实测黄金回收五家店铺排行榜及电话地址推荐白银+铂金+彩金回收 - 盛世金银回收
  • KL散度:从信息论到机器学习的核心度量工具
  • TikTok矩阵账号如何抢流量?多账号之间的推荐机制与权重分配逻辑
  • 南平市黄金回收店铺排行榜及电话地址推荐 2026实测五家诚信优选实体门店 - 大熊猫898989
  • 2026年6月水利工程雷达液位计十大品牌权威推荐:国产力量主导下的技术突围与市场格局 - 仪表品牌榜
  • JMeter常数吞吐量定时器五大模式详解与实战选型指南
  • 工业物联网通信技术实战:无线传感网络与电力线载波通信设计
  • 修行-能量
  • CRUD别硬写了,你的Agent军团已就位
  • 桂林市2026年实测黄金回收五家店铺排行榜及电话地址推荐白银+铂金+彩金回收 - 盛世金银回收
  • AI Agent事前体检报告:可解释的执行前风险预测
  • 梅州市2026年实测黄金回收五家店铺排行榜及电话地址推荐白银+铂金+彩金回收 - 盛世金银回收
  • DLOS v2.0:一种基于规则与LLM协同的AI执行型操作系统内核设计与实现
  • Agent Runtime层的OS时刻:Session日志化与Sandbox cattle化
  • 海口市2026年实测黄金回收五家店铺排行榜及电话地址推荐白银+铂金+彩金回收 - 盛世金银回收