Python模块:自定义模块的创建与调用方法

Python模块:自定义模块的创建与调用方法

Python模块:自定义模块的创建与调用方法

一、开篇:写一个自己的模块

你已经用了很多内置模块(mathrandomos…),现在是时候创建你自己的模块了。好消息是:创建一个模块就是创建一个.py文件——没有复杂的配置,没有特殊的语法。

⌨️ 来吧,从一个简单的工具模块开始:

# 创建一个文件:utils.py# 这就是一个模块!# utils.py 内容:""" 通用工具函数模块(utils) 提供常用的辅助函数:数据验证、格式化、字符串处理等。 """defread_number(prompt="请输入数字: "):"""读取用户输入的数字(带错误处理)"""whileTrue:try:returnfloat(input(prompt))exceptValueError:print("输入无效,请输入一个数字。")defclamp(value,min_val,max_val):"""将值限定在[min_val, max_val]范围内"""returnmax(min_val,min(value,max_val))deftruncate(text,max_length,suffix="..."):"""截断文本到指定长度"""iflen(text)<=max_length:returntextreturntext[:max_length-len(suffix)]+suffix# 使用(在同一个文件或另一个.py文件中):# import utils# age = utils.read_number("请输入年龄: ")# score = utils.clamp(age, 0, 150)

💡 创建自定义模块就是如此简单。但真正的艺术在于组织模块:把什么放在一起、怎么命名、怎么处理模块级别的可执行代码,以及如何让模块既可以直接运行又可以被导入。

二、创建自定义模块

2.1 基本创建和导入

# 假设当前目录结构:# my_project/# ├── main.py# └── calculator.py ← 我们要创建的模块# ===== calculator.py ====="""计算器模块——提供基本数学运算"""defadd(a,b):returna+bdefsubtract(a,b):returna-bdefmultiply(a,b):returna*bdefdivide(a,b):ifb==0:raiseValueError("除数不能为零")returna/bdefpower(base,exp):returnbase**exp# 模块级常量PI=3.141592653589793E=2.718281828459045# ===== main.py =====importcalculatorprint(calculator.add(10,5))# 15print(calculator.divide(10,3))# 3.3333333333333335print(calculator.PI)# 3.141592653589793

2.2 模块文件命名规则

# ⚠️ 模块命名注意事项:# 1. 不能和Python内置模块重名# ❌ 不要创建:math.py、random.py、json.py、os.py# 这会"遮蔽"标准库的同名模块!# 2. 不能和已安装的第三方库重名# ❌ 如果装了requests库,不要创建 requests.py# 3. 使用小写字母和下划线(PEP 8)# ✅ utils.py, data_processor.py, email_service.py# ❌ Utils.py, DataProcessor.py, email-service.py# 4. 避免使用Python关键字# ❌ class.py, import.py, from.py, if.py# 5. 使用有意义的名字# ✅ user_manager.py# ❌ um.py, stuff.py, temp.py

2.3 模块中的可执行代码

# ⚠️ 注意:导入模块时,模块中的所有顶层代码都会执行!# ===== demo_module.py =====print("模块被加载了!")# ← 这行会在import时执行!NAME="demo_module"VERSION="1.0.0"classDemo:"""示例类"""passdefgreet():print(f"Hello from{NAME}!")# ✅ 好的做法:只在模块中定义(无副作用的顶层代码)# ❌ 坏的做法:在模块顶层执行有副作用的操作# 示例:一个模块的顶层代码对比# 好的模块""" 连接配置和工具函数 """DATABASE_URL="postgresql://localhost/mydb"defconnect():"""连接到数据库"""pass# 坏的模块""" 这个模块在导入时就连接数据库——不好! """# db = connect() # 先注释掉——每次import都连接数据库!浪费且不可控# data = load_all_data() # 同样的问题

三、模块的组织和最佳实践

3.1 功能相关的代码放在同一个模块

# ✅ 好的组织# user_service.py —— 用户相关的所有业务逻辑# email_utils.py —— 邮件发送相关的工具函数# validators.py —— 数据验证函数集合# config.py —— 应用配置常量# ❌ 不好的组织# everything.py —— 所有函数混在一起# helpers.py —— "杂项"模块(当文件名就是"各种帮助函数"时,往往意味着缺乏组织)

3.2 实战:创建一组项目模块

# 项目结构:# my_project/# ├── main.py# ├── validators.py —— 数据验证# ├── formatters.py —— 格式化输出# └── converters.py —— 数据转换# ===== validators.py ====="""数据验证模块"""importredefis_valid_email(email):"""验证邮箱格式"""pattern=r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'returnbool(re.match(pattern,email))defis_valid_phone(phone):"""验证手机号(中国)"""pattern=r'^1[3-9]\d{9}$'returnbool(re.match(pattern,phone))defis_strong_password(password):"""验证密码强度:至少8位,包含字母和数字"""return(len(password)>=8andany(c.isalpha()forcinpassword)andany(c.isdigit()forcinpassword))# ===== formatters.py ====="""格式化输出模块"""defformat_currency(amount,symbol="¥"):"""格式化金额"""returnf"{symbol}{amount:,.2f}"defformat_percent(value,decimals=1):"""格式化百分比"""returnf"{value*100:.{decimals}f}%"defformat_table(headers,rows,col_widths=None):"""格式化表格"""ifcol_widthsisNone:col_widths=[max(len(str(row[i]))forrowin[headers]+rows)foriinrange(len(headers))]lines=[" | ".join(str(h).ljust(w)forh,winzip(headers,col_widths))]lines.append("-+-".join("-"*wforwincol_widths))forrowinrows:lines.append(" | ".join(str(c).ljust(w)forc,winzip(row,col_widths)))return"\n".join(lines)# ===== main.py =====importvalidatorsimportformatters# 使用print(validators.is_valid_email("test@example.com"))# Trueprint(validators.is_strong_password("abc12345"))# Trueheaders=["姓名","年龄","城市"]rows=[("张三","25","北京"),("李四","30","上海")]print(formatters.format_table(headers,rows))

四、总结

创建自定义模块就是把代码组织到.py文件中——简单自然。好的模块组织让项目结构清晰,代码复用变得轻松。

💡核心要点:

  1. 一个.py文件 = 一个模块——没有特殊语法
  2. 命名要规范——小写+下划线,不跟标准库冲突
  3. 警惕顶层可执行代码——import时会执行,避免副作用
  4. 功能相关放一起——一个模块一个明确职责
  5. 模块文档——模块的docstring说明模块的用途

✅ 模块化思维:当你发现自己在不同文件中复制粘贴同样的函数时,就该把它提取到独立模块中了。