1:函数基本知识
python
def 函数名字(参数1, 参数2):
# 这里写具体的处理逻辑(加工过程)
# ...
return 最终的结果
-
def(Define): Python 的专属起手式,告诉电脑"我现在要开始制造一个函数了"。 -
括号
(): 必不可少!这是榨汁机的投料口,里面留的空位叫"参数"。 -
冒号
:和 缩进: 和if判断、for循环一样,冒号后面的缩进区域,代表这些代码都属于这个函数的"内部领地"。 -
return: 函数的出口。它负责把处理好的结果扔回到外面的世界。
例子:
python
# 我们造一个计算两个数字相加的函数,取名叫 add_numbers
def add_numbers(num1, num2):
result = num1 + num2
# 处理完毕,把结果交出去
return result
# 第二步:使用榨汁机 (调用函数)
final_juice = add_numbers(10, 20)
print(f"拿到的最终结果是: {final_juice}")
2:函数参数与返回值
最基础的方式:
python
def introduce(name, age):
print(f"大家好,我是{name},今年{age}岁。")
# 必须先传 name,再传 age
introduce("王林", 18)
关键字参数:
python
# 打乱顺序也没关系,因为指名道姓了
introduce(age=18, name="王林")
缺省参数 / 默认参数(自带默认配置):在定义函数时,你可以给某个参数提前设定一个"默认值"。如果调用时不传这个参数,电脑就用默认的;如果传了,就用你传的覆盖掉默认的。
python
# 默认加糖,如果不特殊说明,sugar 就是 True
def make_coffee(type, sugar=True):
if sugar:
print(f"制作一杯【加糖】的{type}咖啡")
else:
print(f"制作一杯【无糖】的{type}咖啡")
make_coffee("拿铁") # 没传 sugar,默认加糖
make_coffee("美式", sugar=False) # 传了 False,覆盖默认值,变成无糖
返回值:可以反复多个
当 return 多个值时,Python 会自动把它们组包成一个元组!
python
def get_student_score():
# 经过一系列复杂查询...
# 一次性返回三个数据
return "王林", 95, 100
# 外面准备三个变量,完美接住(解包)
name, math, english = get_student_score()
print(f"学生: {name}, 数学: {math}, 英语: {english}")
3:函数说明文档
python
def add_numbers(num1, num2):
"""
计算两个数字的和
这个函数接收两个参数 num1 和 num2,返回它们的和。
"""
result = num1 + num2
# 处理完毕,把结果交出去
return result
这是写在 Python 函数、类或者文件开头的说明,紧挨着定义,使用三引号 """ """ 包裹。目前 AI 和数据科学领域最流行的是 Google 风格,因为它非常清晰易读。
4:嵌套调用函数
python
# 工人 A:专门负责洗菜
def wash_vegetables(veg_name):
print(f" -> [洗菜工] 正在疯狂清洗 {veg_name}...")
return f"干净的{veg_name}"
# 工人 B:专门负责炒菜
def fry(ingredient):
print(f" -> [炒菜工] 正在大火爆炒 {ingredient}...")
return f"一盘美味的{ingredient}"
# 包工头:统筹做一道菜 (这里发生了【嵌套调用】)
def make_dish(raw_veg):
print(f"【主厨指令】开始制作 {raw_veg} 料理!")
# 嵌套调用 1:呼叫洗菜工,把生菜递过去,接住洗好的菜
clean_veg = wash_vegetables(raw_veg)
# 嵌套调用 2:呼叫炒菜工,把洗好的菜递过去,接住炒好的菜
final_food = fry(clean_veg)
print("【主厨指令】全部完工,准备上菜!")
return final_food
# --- 实际运行测试 ---
print("=========== 厨房开始运作 ===========")
my_dinner = make_dish("西红柿")
print(f"=========== 最终得到: {my_dinner} ===========")
当代码执行到内部调用的函数时,会先暂停当前的工作,跑去把内部函数的工作全部做完,带着结果回来,再继续往下执行。
5:案例

python
# ==========================================
# 任务 1:计算三角形面积
# ==========================================
def calc_triangle_area(base, height):
"""根据底和高计算三角形面积"""
area = base * height / 2
return area
# 测试任务 1
print(f"底为 10,高为 5 的三角形面积是: {calc_triangle_area(10, 5)}")
# ==========================================
# 任务 2:计算字符串中元音字母的个数
# ==========================================
def count_vowels(text):
"""计算传入字符串中元音字母的个数"""
count = 0 # 准备一个计数器
vowels = "aeiouAEIOU" # 定义目标元音字母集合
for char in text:
if char in vowels:
count += 1
return count
# 测试任务 2
test_str = "Hello Python, Hello AI"
print(f"'{test_str}' 中共有 {count_vowels(test_str)} 个元音字母")
# ==========================================
# 任务 3:计算班级成绩单的最高分、最低分、平均分
# ==========================================
def analyze_scores(scores):
"""计算成绩的最高分、最低分、平均分并返回"""
# 考虑到列表可能为空,做一个简单的安全防护
if not scores:
return 0, 0, 0.0
highest = max(scores) # 获取最高分
lowest = min(scores) # 获取最低分
# sum(scores) 算出总分,len(scores) 算出人数
# round(数据, 1) 表示保留 1 位小数
average = round(sum(scores) / len(scores), 1)
# Python 的特色:一次性返回多个值(自动打包成元组)
return highest, lowest, average
# 测试任务 3
my_class_scores = [98, 76, 85, 100, 62, 88]
max_s, min_s, avg_s = analyze_scores(my_class_scores) # 接收多个返回值(解包)
print(f"成绩单分析 -> 最高分: {max_s}, 最低分: {min_s}, 平均分: {avg_s}")

if not scores: return 0, 0, 0.0:代码解析:
这是因为 Python 有一个极其好用的特性:所有的数据都可以直接被当做 True(真)或 False(假)来判断。
-
非空的数据 (比如
[98, 76]、"Hello"、5):默认被当做True。 -
空的数据或零 (比如
[]空列表、""空字符串、0、None):默认被当做False。 -
假设传入的是空列表
scores = [](班级里没学生):-
scores是空的,所以它等同于False。 -
not False就会反转变成True。 -
条件成立,代码进入
if内部,执行return 0, 0, 0.0。 -
函数立刻下班,扔出三个 0 作为默认结果。
-
-
假设传入了正常成绩
scores = [98, 76]:-
scores里面有东西,所以它等同于True。 -
not True就会反转变成False。 -
条件不成立,代码跳过 这个
if块。 -
继续往下执行
max()、min()和求平均分的正常逻辑。
-
6:函数中的变量作用域
写在所有函数外面的变量,就是全局变量。
python
# 挂在大厅的黑板(全局变量)
today_special = "红烧肉"
def customer_A():
# 函数里面可以直接看到外面的黑板
print(f"顾客A看到了今日特价:{today_special}")
customer_A() # 结果: 顾客A看到了今日特价:红烧肉

写在某一个函数内部的变量,就是局部变量。
python
def chef_work():
# 后厨的私密小纸条(局部变量)
secret_recipe = "加一勺蜂蜜"
print(f"厨师在用秘方:{secret_recipe}")
chef_work() # 正常运行
# 如果你尝试在外面偷看后厨的秘方,电脑会直接报错!
# print(secret_recipe) # ❌ 报错:NameError,因为外面根本看不到 secret_recipe
假设大厅的黑板上写着 price = 10(全局变量),但是厨师在后厨里自己又写了一张小纸条 price = 50。这时候会发生什么?

python
price = 10 # 大厅的黑板
def change_price():
price = 50 # 电脑认为:你新建了一个同名的后厨小纸条,不关外面的事
print(f"后厨里的价格是: {price}")
change_price()
print(f"大厅里的价格依然是: {price}") # 结果还是 10!外面没被修改!

如果厨师真的觉得外面的价格定低了,必须在后厨修改大厅的黑板 ,该怎么办? 只需要用 global 关键字大喊一声:"我要改外面的那个大黑板!"
python
price = 10
def real_change_price():
global price # 重点:告诉电脑,我接下来用的 price,就是外面大厅的那个!
price = 50 # 这次,外面的黑板被成功修改了
real_change_price()
print(f"大厅里的价格变成了: {price}") # 结果是 50!

7:传参数方式
1:位置传参,关键字传参
python
def introduce(name, age, city):
print(f"我叫{name},今年{age}岁,来自{city}。")
# 1. 位置传参:必须按照 name, age, city 的顺序
introduce("王林", 18, "赵国")
# 2. 关键字传参:指名道姓,顺序打乱也没关系
introduce(city="楚国", name="韩立", age=20)
# 3. 混合使用:位置参数必须在关键字参数的前面!
introduce("曾牛", city="朱雀星", age=50)

2:默认参数
python
# gender="男" 就是默认参数
def register(username, password, gender="男"):
print(f"注册成功:用户[{username}], 密码[{password}], 性别[{gender}]")
# 不传第三个参数,默认使用 "男"
register("admin", "123456")
# 传入新数据,覆盖默认值
register("alice", "abcdef", gender="女")

3:动态参数
有时候,你不确定调用函数时会传入多少个参数
-
*args(位置不定长): 接收所有多出来的"位置参数",并把它们打包成一个元组 -
**kwargs(关键字不定长): 接收所有多出来的"关键字参数",并把它们打包成一个字典
python
# 1. 测试 *args
def make_sandwich(*ingredients):
# ingredients 此时是一个元组:('牛肉', '生菜', '煎蛋')
print("你的三明治配料有:", ingredients)
make_sandwich("牛肉", "生菜", "煎蛋")
# 2. 测试 **kwargs
def create_user(**info):
# info 此时是一个字典:{'name': '王林', 'level': 99}
print("创建用户,详细信息:", info)
create_user(name="王林", level=99, sect="恒岳派")
# 3. 终极组合:所有参数通吃
def super_function(a, b, *args, **kwargs):
print(f"固定参数 a={a}, b={b}")
print(f"多余的位置参数 args={args}")
print(f"多余的关键字参数 kwargs={kwargs}")
super_function(1, 2, 3, 4, 5, name="韩立", weapon="掌天瓶")

案例二:
python
def calc_data(*args, **kwargs):
"""
计算传入数字的最小值、最大值和平均值
:param args: 不定长位置参数,接收所有需要计算的数字
:param kwargs: 不定长关键字参数,接收配置项 (round: 保留小数位数, print: 是否内部打印)
"""
# 安全阀:如果没有传入任何数字,直接结束,防止 max/min/len 报错
if not args:
return 0, 0, 0.0
# 1. 核心计算
min_data = min(args)
max_data = max(args)
avg_data = sum(args) / len(args)
# 2. 动态配置开关 A:四舍五入
if kwargs.get("round") is not None:
avg_data = round(avg_data, kwargs.get("round"))
# 3. 动态配置开关 B:内部打印
# 注意:字典 get 找不到键时默认返回 None,None 在条件判断中等同于 False
if kwargs.get("print"):
print(f"计算出来的最小值: {min_data}, 最大值: {max_data}, 平均值:{avg_data}")
# 4. 返回打包好的结果
return min_data, max_data, avg_data
# ==========================================
# 测试场景 1:完美复刻截图中的调用
# 传入一堆数字,要求保留 4 位小数,不打印内部信息
# ==========================================
print("--- 测试场景 1 ---")
result1 = calc_data(2, 7, 9, 10, 45, 73, 37, 93, 92, 111, 222, round=4, print=False)
print(f"最终拿到的返回值: {result1}")
# ==========================================
# 测试场景 2:开启内部打印,且不传入 round
# ==========================================
print("\n--- 测试场景 2 ---")
result2 = calc_data(10, 20, 30, 40, print=True)
