函数、模块与包
-
- 前言
- [1. 函数基础](#1. 函数基础)
-
- [1.1 定义](#1.1 定义)
- [1.2 参数与返回值](#1.2 参数与返回值)
- [1.3 函数的说明文档](#1.3 函数的说明文档)
- [1.4 函数嵌套调用](#1.4 函数嵌套调用)
- [2. 函数进阶](#2. 函数进阶)
-
- [2.1 函数变量的作用域](#2.1 函数变量的作用域)
- [2.2 函数参数](#2.2 函数参数)
-
- [2.2.1 传参方式](#2.2.1 传参方式)
- [2.2.2 默认参数](#2.2.2 默认参数)
- [2.2.3 不定长参数](#2.2.3 不定长参数)
- [2.2.4 参数类型](#2.2.4 参数类型)
- [2.2.5 匿名函数](#2.2.5 匿名函数)
- [2.3 类型注解](#2.3 类型注解)
-
- [2.3.1 变量类型注解](#2.3.1 变量类型注解)
- [2.3.2 函数类型注解](#2.3.2 函数类型注解)
- [3. 模块](#3. 模块)
-
- [3.1 介绍](#3.1 介绍)
- [3.2 导入模块](#3.2 导入模块)
- [3.3 自定义模块](#3.3 自定义模块)
-
- [3.3.1 定义](#3.3.1 定义)
- [3.3.2 测试函数](#3.3.2 测试函数)
- [3.3.3 设置导入功能](#3.3.3 设置导入功能)
- [3.4 包](#3.4 包)
-
- [3.4.1 定义](#3.4.1 定义)
- [3.4.2 创建](#3.4.2 创建)
- [3.4.3 导入方式](#3.4.3 导入方式)

🎬 博主名称: 超级苦力怕
🔥 个人专栏: 《Python 基础》
🚀 每一次思考都是突破的前奏,每一次复盘都是精进的开始!
前言
本文将系统讲解 Python 中函数的定义、参数、返回值、作用域 等核心概念,并进一步介绍模块与包的使用,帮助你写出更优雅、高效的代码。
1. 函数基础
1.1 定义
函数:组织好的、可重复使用、用于实现特定功能的代码片段,如常用的**print()**就是函数,函数的定义语法如下
python
# 定义函数
def 函数名(参数列表):
函数体
......
return 返回值
# 调用函数
函数名(参数)
#示例
def out_line():
print('---')
#调用函数
out_line()
特点:
- 函数必须先定义,再调用
- 函数定义时不会执行,只有调用函数才会执行
- 函数中通过缩进描述归属关系
注意:函数定义时,参数和返回值可有可无,可以根据需求先做模板,再做调整。
1.2 参数与返回值
在定义函数时,可以根据需求,指定参数与返回值。
python
def rectangle_area(l,w):
area = l * w
return area
area = rectangle_area(20,10) # area = 200
示例代码
python
def circle_area_len(r):
area = round(3.14 * r * r, 1)
circumference = round(2 * 3.14 * r, 1)
return area, circumference
al = circle_area_len(10)
print(al) # (314.0, 62.8)
print(type(al)) #<class 'tuple'>
area, len = circle_area_len(10) # 解包,可以让多个返回值封装到元组中
print(area) #314.0
print(len) #62.8
注意:
- 函数定义时如果有多个参数,使用
,分隔- return 语句只有返回功能,没有打印功能,需要结合 print() 实现打印
1.3 函数的说明文档
函数的说明文档(Docstring) 是写在函数开头,用三个引号包裹的字符串,用于解释函数的功能、参数、返回值等信息,方便调用者清楚函数的具体作用及细节。
python
# 定义一个函数,根据半径,计算圆的周长、面积
def circle_area_len(r):
"""
这部分是函数的说明文档,通常描述函数的参数、函数的返回值
该函数用于根据圆的半径,计算圆的面积和圆的周长
:param r: 圆的半径
:return: 圆的面积,圆的周长
"""
return 3.14 * r * r, 2 * 3.14 * r
al = circle_area_len(10)
print(al) #(314.0, 62.800000000000004)
拓展:计算机用二进制表示十进制小数时,有些小数(比如0.8)无法精确表示,只能近似存储,所以计算后就会出现这种微小误差。
注意:可以通过鼠标悬浮在函数上查看说明文档(推荐),或者使用 help 函数查看说明文档
python
help(circle_area_len)
#输出结果如下
circle_area_len(r)
该函数用于根据圆的半径,计算圆的面积和圆的周长
:param r: 圆的半径
:return: 圆的面积,圆的周长

1.4 函数嵌套调用
嵌套调用指的是在一个函数中,又调用了另外一个函数,具体如下所示。
python
# 在 Pycharm 中,可以点击左侧行数,进行断点,这时候运行选择DeBug,就会根据断点处进行停留。
def function_a():
print("a ... before")
function_b()
print("a ... after") # 第二个函数执行完才会执行当前语句
def function_b():
print("b ... before")
function_c()
print("b ... after") # 第三个函数执行完毕后才会执行当前语句
def function_c():
print("c ...")
function_a()
运行结果
shell
a ... before
b ... before
c ...
b ... after
a ... after
函数调用遵循栈结构(先进后出),最后被调用的函数最先返回。
执行流程:第一个函数先执行 before,开始执行第二个函数,第二个函数执行 before,开始执行第三个函数,然后第二个函数执行 after,第一个函数执行 after。
拓展:栈可以看作是一个水杯,放进去的东西在最底面,最后才能拿出来
2. 函数进阶
2.1 函数变量的作用域
变量的作用域指的是变量的作用范围(标注这个遍历在哪里可以使用,在哪里不可以使用)
一般来说,我们会把变量分为 局部变量 和 全局变量 ,局部变量只能在函数使用,但是可以使用 global 关键字,声明函数内部的值为全局变量。
补充
- 全局变量:在函数之外定义的变量,称之为全局变量,在整个文件中(包括函数内)都可以使用
- 局部变量:在函数内部定义的变量,只能够在函数内部访问,外部无法访问(函数执行完毕会自动销毁)
- 在项目开发时,尽量避免使用全局变量,这样代码会难以维护,而 global 关键字常用于在程序的状态、配置和计数器等场景。
全局变量的使用方法:先定义变量,再进行使用
python
# 定义全局变量
count = 0 # 全局变量 count,初始值为 0
total_score = 100 # 全局变量 total_score,初始值为 100
def add_score(score):
global total_score # 声明要使用全局变量
total_score = total_score + score # 在函数内部修改全局变量的值
def increment_count():
global count # 声明要使用全局变量
count = count + 1 # 在函数内部修改全局变量的值
# 调用前查看全局变量
print(count) # 0
print(total_score) # 100
# 调用函数
add_score(20) # 将全局变量 total_score 增加 20
increment_count() # 将全局变量 count 增加 1
increment_count() # 再次将全局变量 count 增加 1
# 调用后查看全局变量(已被函数修改)
print(count) # 结果:2
print(total_score) # 结果:120
2.2 函数参数
2.2.1 传参方式
传参方式指的是,在调用函数时,传递实参的方式,分为 位置参数 、关键字参数
位置参数 :调用函数时根据函数定义时的位置传递参数,也就是参数顺序与定义函数时参数顺序完全一致
python
# 定义函数
def reg_stu(name, age, gender, city):
print(f"注册成功,姓名:{name}, 年龄:{age}, 性别:{gender}, 城市:{city}")
return {"name": name, "age": age, "gender": gender, "city": city}
# 调用函数
stu = reg_stu("张三", 18, "男", "北京") # 对应着 name、age、gender、city
print(stu)
关键字参数 :调用函数时以函数定义形参名称作为关键字,以" 键=值 "的形式来传递参数(不要求顺序)
拓展:如果位置参数与关键字参数混用,关键字参数必须在位置参数之后
python
# 定义函数
def reg_stu(name, age, gender, city):
print(f"注册成功,姓名:{name}, 年龄:{age}, 性别:{gender}, 城市:{city}")
return {"name": name, "age": age, "gender": gender, "city": city}
# 调用函数
stu = reg_stu(name="张三", age=18, gender="男", city="北京")
print(stu)
stu2 = reg_stu(gender="男", name="王武", city="上海", age=22)
print(stu2)
stu2 = reg_stu("赵四", 28, gender="男", city="上海") # 这里赵四就是位置参数,男 和 上海 是关键字参数
print(stu2)
总结:
- 位置参数简洁高效,但当参数较多或含义不明确时,容易因顺序错误导致问题,适合参数较少(如不超过3个)的场景
- 关键字参数优点可读性强 、易维护 、易扩展 ,缺点代码繁琐,适合参数多,容易混淆的场景使用
2.2.2 默认参数
默认参数:又称为缺省参数,用于在定义函数的时候,为参数提供默认值,调用函数可以不传递有默认值的参数
python
# 定义函数
def reg_stu(name, age, gender, city='北京'):
print(f"注册成功,姓名:{name}, 年龄:{age}, 性别:{gender}, 城市:{city}")
return {"name": name, "age": age, "gender": gender, "city": city}
# 调用函数
stu = reg_stu("张三", 18, "男")
print(stu)
stu = reg_stu("赵四", 22, "男", "深圳")
print(stu)
补充:
- 默认参数必须没有默认值的参数列表后面,一个函数可以设置多个默认参数。
- 函数调用时,如果为默认参数传递了值,就会修改默认值,如果没有传递该参数,则直接使用默认值。
2.2.3 不定长参数
不定长参数指可以传递多个参数,且不固定长度,有两种方法
- 使用
*变量名的方式接收位置参数,用于处理数量不稳定的数据,会将多个数据转化为元组 - 使用
**变量名的方式接收关键字参数,用于处理数量不确定的选项(函数的配置参数,用来定制函数的行为),会将多个数据转化为字典
python
# 定义函数,可以通过 round 的值去控制小数位数,通过 print 的值控制是否打印
def calc_data(*args, **kwargs):
min_data = min(args)
max_data = max(args)
avg_data = sum(args) / len(args)
if kwargs.get("r") is not None:
avg_data = round(avg_data, kwargs.get("r"))
if kwargs.get("p"):
# 计算出来的最小值: 2, 最大值: 45, 平均值:14.6
print(f"计算出来的最小值: {min_data}, 最大值: {max_data}, 平均值:{avg_data}")
return min_data, max_data, avg_data
# 调用函数
print(calc_data(2, 7, 9, 10, 45, r=3, p=True))
2.2.4 参数类型
普通参数:数字、布尔、字符串、列表、元组、集合、字典等。
特殊参数:函数。
函数可以被作为参数,例如下面时模拟计算机,可以指定传递的参数(函数),从而选择加减乘除。
python
## 加
def add(x, y):
return x + y
## 减
def subtract(x, y):
return x - y
## 乘
def multiply(x, y): # 1个用法
return x * y
## 除
def divide(x, y):
return x / y
## 计算
def calc(x, y, oper): # 1个用法
return oper(x, y)
# 这里可以通过复制,去调用不同的函数
print(calc(x=10, y=20, oper=multiply)) # 200
2.2.5 匿名函数
匿名函数指的是没有名称的函数,需要通过lambda表达式来声明函数,可以简化简单函数的编写(单行表达式)。
python
# 定义匿名函数
lambda 参数列表: 表达式
# 示例
lambda : print('---')
# 无参数的lambda函数
func1 = lambda: print('---')
# Lambda x, y: x + y
# 有两个参数的lambda函数
func2 = lambda x, y: x + y
# 调用示例
func1() # 输出: ---
result = func2(10, 20)
print(result) # 输出: 30
注意:
- 函数逻辑较简单,且只在一个地方使用时,考虑使用匿名函数简化书写(通常作为高阶函数的参数使用)
- 匿名函数可以返回结果,也可以不返回结果(默认返回None),返回不需要写return,表达式的运行结果就是要返回的结果
2.3 类型注解
在进行运算的时候,可能会出现预期不符的现象,例如本该是 int 类型的数,不小心传入了String类型,但由于Python是动态语言,导致运行前不显示错误,这个时候就需要类型注解来提醒。
类型注解是Python中的语法特性,用于明确标识变量、函数参数和返回值的数据类型,当使用类型注解时,调用函数或值,会进行提醒,不影响运行。
2.3.1 变量类型注解
变量类型注解定义语法如下
python
# 定义变量
变量名:变量类型 = 值
# 示例
a:int = 695
b:list[int|str] = ["A","C"] # 注意,当存储数据容器的时候,可以指定一个数据类型,也可以指定多个数据类型
优点
- 代码结构更清晰、代码逻辑更安全、更易维护。
- 更准确的代码自动提示
- 提前发现代码潜在问题
拓展 :类型推断
类型推断是指Python解释器自动判断出变量、表达式或函数返回值的数据类型的能力,无需开发中显式声明
2.3.2 函数类型注解
为函数添加类型注解,主要为函数的参数和返回值添加类型注解,语法如下
python
# 语法
def 函数名(参数名:参数类型) -> 返回值类型:
return ....
# 示例
def calc(scores: list[int]) -> float:
return sum(scores) / len(scores)
def calc_data(scores: list[int]) -> tuple[int, int, float]:
max_v = max(scores)
min_v = min(scores)
avg_v = sum(scores) / len(scores)
return max_v, min_v, avg_v
函数类型注解常用于 团队开发 、长期维护的项目
3. 模块
3.1 介绍
Python模块(module):一个.py就是一个模块,模块是Python程序的基本组织单位,在模块中可以定义变量、函数、类、可执行的代码。
模块与模块之间是可以互相引用的,Python官方给我们提供了很多自定义模块,比如math(数学计算)、random(随机数)等,通过 import 进行引用,示例如下:
python
# 随机点名器
import random
# 人物列表
names = ["王林", "李慕妮",
"许立国", "韩立",
"涛哥", "莫厉海",
"十三", "虎吨",
"红蝶", "天运子"]
print(random.choice(names))
通过将不同代码放在不同模块里,不仅避免了命名冲突 ,而且随时拿取,提高代码复用性 、降低开发门槛
3.2 导入模块
在使用模块提供的功能前,我们需要先导入,再使用,具体语法如下:
| 导入形式 | 代码样例 | 调用方式 | 调用方式 |
|---|---|---|---|
| import 模块名 | import random, os | 模块名.功能名 | random.randint(10, 100) |
| import 模块名 as 别名 | import random as rd | 别名.功能名 | rd.randint(10, 100) |
| from 模块名 import 功能名 | from random import randint, choice | 功能名 | randint(10, 100) |
| from 模块名 import 功能名 as 别名 | from random import randint as rint | 别名 | rint(10, 100) |
| from 模块名 import * | from random import * | 功能名 | randint(10, 100) |
python
# 使用 import 模块名 as 别名
import random as rd
# 使用别名调用功能
number = rd.randint(1, 100) # 生成1-100之间的随机数
name = rd.choice(["张三", "李四", "王五"]) # 随机选择一个名字
print(f"随机数字: {number}") # 35
print(f"随机姓名: {name}") # 王五
注意:
- 在 PyCharm 或大多数其他编译器中,输入对应的方法,会自动导入对应模块,不需要手动导入模块。
- 导入模块语句一般写在py文件开头,是因为我们先导入、再使用,且更加直观
3.3 自定义模块
3.3.1 定义
当开发一些复杂的项目,为了让项目结构清晰,方便项目的维护管理 及 代码的复用,可能会把一个项目拆分为若干个模块,我们可以自定义模块并使用,获取里面的变量和函数。
python
# my_math.py - 自定义数学模块
def add(a, b):
"""加法函数"""
return a + b
def multiply(a, b):
"""乘法函数"""
return a * b
PI = 3.14159 # 模块中的变量
python
# 引用刚才的模块
from my_math import add, PI
print(add(20, 30)) # 直接调用,不需要模块名 50
print(PI)
拓展:建议模块的名字遵循 python标识符定义,规范命名。
3.3.2 测试函数
测试函数:Python中内置变量__name__,标识当前模块名字,执行当前模块会执行测试函数内的代码,作为模块导入时,测试函数不执行。
python
# my_math.py - 自定义数学模块
def add(a, b):
"""加法函数"""
return a + b
def multiply(a, b):
"""乘法函数"""
return a * b
PI = 3.14159 # 模块中的变量
# 当直接运行此文件时执行测试,作为模块导入时不执行
if __name__ == "__main__":
print("\n手动测试示例:")
print(add(10, 20)) # 30
print(multiply(5, 6)) # 30
print(PI) # 3.14159
拓展 :Python 借鉴了其他语言的程序入口 main,放运行文件时,会设置内置变量 name = "main ",但如果被导入,他会设置为模块名,这就是为什么作为模块导入时不执行的原因
3.3.3 设置导入功能
__all__是一个模块级别特殊变量,可以指定 from 模块名 import *导入哪些功能
python
# all 前后都是两个_
__all__ =["log_separator1","log_separator2","PI"]
PI = 3.1415926
NAME = "超级苦力怕"
def log_separator1():
print("_ * 30")
def log_separator2():
print("+ * 30")
def log_separator3():
print("# * 30")
def log_separator4():
print("* * 30")
3.4 包
3.4.1 定义
包:本质上是一个文件夹,文件夹中可以包括多个python模块,文件夹还包含了__init__.py(描述当前包的信息)
作用:用来管理多个模块,包本质上也是一个模块。
3.4.2 创建
我们在Pycharm右键文件夹,创建一个包

在包内会自动包含一个__init__模块,我们可以描述包的基本信息,例如
python
# 版本
__version__ = "1.0.0"
__author__ ="Coolipa"
# 当导入全部时,导入哪些模块
__all__ = ["my_fun"]
补充:像上述的__name__,还是这里的__version__,只要前面有两个下划线,代表的就是特殊变量。
3.4.3 导入方式
| 导入形式 | 代码样例 | 调用方式 | 调用方式 |
|---|---|---|---|
| import 包名.模块名 | import utils.my_fun | 包名.模块名.功能名 | utils.my_fun.log_separator1() |
| from 包名 import 模块名 | from utils import my_fun | 模块名.功能名 | my_fun.log_separator1() |
| from 包名 import * | from utils import * | 模块名.功能名 | my_fun.log_separator1() |
| from 包名.模块名 import 功能名 | from utils.my_fun import log_separator1 | 功能名 | log_separator1() |
| from 包名.模块名 import * | from utils.my_fun import * | 功能名 | log_separator1() |
- 如果本文对你有帮助:欢迎点赞、收藏,让更多正在学 Python 的同学看到。
- 遇到问题或有不同理解:可以在评论区留言,一起讨论、互相学习。
- 想系统看更多内容:可以关注专栏《Python 基础》,一起把基础打牢。
