函数专题1
知识点回顾:
- 函数的定义
- 变量作用域:局部变量和全局变量
- 函数的参数类型:位置参数、默认参数、不定参数
- 传递参数的手段:关键词参数
- 传递参数的顺序:同时出现三种参数类型时
1. 函数的定义:餐厅的菜单
想象你走进一家餐厅,菜单上列出了各种菜品。这些菜品就像是函数,是餐厅为你准备好的“功能”。你可以通过点菜(调用函数)来享受美食(执行功能)。
函数定义:菜单上的每一道菜都有一个名字(函数名),比如“宫保鸡丁”或“红烧肉”。这些名字让你知道你可以点什么菜。
函数的基本写法如下所示: ```python def function_name(parameter1, parameter2, ...): """ Docstring: 描述函数的功能、参数和返回值 (可选但强烈推荐) """ # 函数体: 实现功能的代码 # ... return value # 可选,用于返回结果 ``` - def: 关键字,表示开始定义一个函数。 - function_name: 函数的名称,应遵循Python的命名约定(通常是小写字母和下划线,例如 calculate_area,用英文单词含义和下划线来作为函数名)。 - parameter1, parameter2, ...: 函数的参数(也叫形参),是函数在被调用时接收的输入值。参数是可选的。 - (): 参数列表必须放在圆括号中,即使没有参数,括号也不能省略。 - : 冒号表示函数定义的头部结束,接下来是缩进的函数体。 - Docstring (文档字符串): 位于函数定义第一行的多行字符串(通常用三引号 """Docstring goes here""")。用于解释函数的作用、参数、返回值等。可以通过 help(function_name) 或 function_name.__doc__ 查看。这个写法可选,为了后续维护和查看,建议加上这一段更加规范 - 函数体 (Function Body): 缩进的代码块,包含实现函数功能的语句。 - return value: return 语句用于从函数中返回一个值。如果函数没有 return 语句,或者 return 后面没有值,它会自动返回 None。一个函数可以有多个 return 语句(例如在不同的条件分支中)。
调用函数:你告诉服务员你想要的菜品,比如“我要一份宫保鸡丁”,这就像是在代码中调用一个函数。
1. 不带参数的函数:固定套餐
假设餐厅提供一种“固定套餐”,你不需要告诉服务员任何额外信息,直接点这个套餐就行。
def fixed_meal(): print("这是固定套餐:宫保鸡丁 + 米饭 + 汤")
比喻:你走进餐厅,直接对服务员说:“我要固定套餐。”
执行:服务员知道固定套餐的内容,直接给你准备宫保鸡丁、米饭和汤。
代码调用
fixed_meal() # 输出:这是固定套餐:宫保鸡丁 + 米饭 + 汤
-
2. 带位置参数的函数:点具体菜品
假设你需要点具体的菜品,比如宫保鸡丁和红烧肉,你需要按顺序告诉服务员你想要的菜品。
def order_dishes(dish1, dish2): print(f"您点了:{dish1} 和 {dish2}")
比喻:你对服务员说:“我要宫保鸡丁和红烧肉。”
执行:服务员按照你点的顺序记录下来,准备这两道菜。
代码调用
order_dishes("宫保鸡丁", "红烧肉") # 输出:您点了:宫保鸡丁 和 红烧肉
-
3. 带默认参数的函数:点菜时有默认选项
假设菜单上写明“宫保鸡丁默认不辣”,但你可以选择修改这个默认选项。
def order_dish(dish, spiciness="不辣"): print(f"您点了:{dish},辣度为:{spiciness}")
比喻:你对服务员说:“我要宫保鸡丁。”(默认不辣)
如果你有特殊要求,可以说:“我要宫保鸡丁,辣度中辣。”
执行:服务员按照默认选项准备菜品,除非你有特殊要求。
代码调用
order_dish("宫保鸡丁") # 输出:您点了:宫保鸡丁,辣度为:不辣 order_dish("宫保鸡丁", "中辣") # 输出:您点了:宫保鸡丁,辣度为:中辣
-
4. 带不定参数的函数:点菜时有额外要求
假设你可以有一些额外的要求,比如“多放点花生”或“少放点油”。
def order_dish_with_extra(dish, *extras): print(f"您点了:{dish}") if extras: print("额外要求:", ", ".join(extras)) else: print("没有额外要求")
比喻:你对服务员说:“我要宫保鸡丁,多放点花生,少放点油。”
执行:服务员记录下你的额外要求,并告诉厨师。
代码调用
order_dish_with_extra("宫保鸡丁", "多放点花生", "少放点油") # 输出: # 您点了:宫保鸡丁 # 额外要求: 多放点花生, 少放点油
-
5. 带关键词参数的函数:点菜时明确说明需求
假设你可以通过关键词来明确你的需求,比如“辣度=中辣”或“花生=多放”。
def order_dish_with_keywords(dish, **kwargs): print(f"您点了:{dish}") if kwargs: print("具体要求:") for key, value in kwargs.items(): print(f" {key}: {value}") else: print("没有具体要求")
比喻:你对服务员说:“我要宫保鸡丁,辣度=中辣,花生=多放。”
执行:服务员清楚地记录下你的具体要求,并告诉厨师。
代码调用
order_dish_with_keywords("宫保鸡丁", spiciness="中辣", peanuts="多放") # 输出: # 您点了:宫保鸡丁 # 具体要求: # spiciness: 中辣 # peanuts: 多放
6. 混合参数类型的函数:综合点菜
假设你可以同时使用位置参数、默认参数、不定参数和关键词参数。
def order_complete_meal(dish1, dish2="红烧肉", *extras, **kwargs): print(f"您点了:{dish1} 和 {dish2}") if extras: print("额外要求:", ", ".join(extras)) if kwargs: print("具体要求:") for key, value in kwargs.items(): print(f" {key}: {value}")
比喻:你对服务员说:“我要宫保鸡丁,红烧肉,多放点花生,少放点油,辣度=中辣。”
执行:服务员按照顺序记录你的需求,包括默认选项、额外要求和具体要求。
代码调用
order_complete_meal("宫保鸡丁", "红烧肉", "多放点花生", "少放点油", spiciness="中辣") # 输出: # 您点了:宫保鸡丁 和 红烧肉 # 额外要求: 多放点花生, 少放点油 # 具体要求: # spiciness: 中辣
2. 变量作用域:厨房和餐厅的食材
假设餐厅有两个区域:厨房和餐厅。
局部变量(厨房的食材):厨房里的食材(比如新鲜的鸡肉、蔬菜)只在厨房里使用,厨师用它们来准备菜品。这些食材不会出现在餐厅里,顾客也看不到它们。一旦菜品做好,这些食材就被用完了(变量被销毁)。
全局变量(餐厅的食材):餐厅里有一些食材(比如调料、餐具)是所有人都可以使用的。这些食材不仅厨师可以用,服务员也可以用,甚至顾客也可以看到它们。这些食材在整个餐厅(整个程序)中都是可用的。
print("\n--- 变量作用域示例 ---") global_var = "我是一个全局变量" def scope_test(): local_var = "我是一个局部变量" print(f"在函数内部,可以看到局部变量: '{local_var}'") print(f"在函数内部,也可以看到全局变量: '{global_var}'") # global_var = "尝试在函数内修改全局变量" # 如果没有 global 声明,这会创建一个新的局部变量 global_var # print(f"在函数内部,修改后的 '全局' 变量: '{global_var}'") scope_test() print(f"\n在函数外部,可以看到全局变量: '{global_var}'") # print(f"在函数外部,不能看到局部变量: {local_var}") # 这会产生 NameError,因为 local_var 只在函数内存在
3. 函数的参数类型:点菜的方式
当你点菜时,你可以用不同的方式告诉服务员你的需求。
位置参数(按顺序点菜):你告诉服务员:“我要一份宫保鸡丁,一份红烧肉”。这里,“宫保鸡丁”和“红烧肉”是按顺序告诉服务员的,就像位置参数一样,顺序很重要。
# 带位置参数的函数 def order_dishes(dish1, dish2): # 根据传入的位置参数执行操作 print(f"您点了:{dish1} 和 {dish2}") # 调用函数时,按顺序传入参数 order_dishes("宫保鸡丁", "红烧肉") # 输出:您点了:宫保鸡丁 和 红烧肉
默认参数(默认的菜品选项):假设菜单上写明“宫保鸡丁默认不辣”,如果你没有特别说明,厨师就会按照默认的方式(不辣)来做这道菜。如果你说“我要一份辣的宫保鸡丁”,这就像是传递了一个非默认值。
# 带默认参数的函数 def order_dish(dish, spiciness="不辣"): # 默认参数 spiciness 默认值为 "不辣" print(f"您点了:{dish},辣度为:{spiciness}") # 调用函数时,可以不传默认参数 order_dish("宫保鸡丁") # 输出:您点了:宫保鸡丁,辣度为:不辣 # 也可以传入非默认值 order_dish("宫保鸡丁", "中辣") # 输出:您点了:宫保鸡丁,辣度为:中辣
不定参数(额外的要求):你还可以有一些额外的要求,比如“我要一份宫保鸡丁,多放点花生”或“我要一份红烧肉,少放点油”。这些额外的要求就像是不定参数,可以有也可以没有,数量也不固定。
# 带不定参数的函数 def order_dish_with_extra(dish, *extras): # *extras 是一个元组,包含所有额外的要求 print(f"您点了:{dish}") if extras: print("额外要求:", ", ".join(extras)) else: print("没有额外要求") # 调用函数时,可以传入任意数量的额外要求 order_dish_with_extra("宫保鸡丁", "多放点花生", "少放点油") # 输出: # 您点了:宫保鸡丁 # 额外要求: 多放点花生, 少放点油 # 不传额外要求 order_dish_with_extra("宫保鸡丁") # 输出: # 您点了:宫保鸡丁 # 没有额外要求
4. 传递参数的手段:关键词参数(点菜时说明需求)
当你点菜时,你可以明确告诉服务员你的需求,比如“我要一份宫保鸡丁,辣度是微辣,多放点花生”。这里,“辣度是微辣”和“多放点花生”就像是关键词参数,你通过参数名(辣度、花生)来明确你的需求。
# 带关键词参数的函数
def order_dish_with_keywords(dish, **kwargs):
# **kwargs 是一个字典,包含所有关键词参数
print(f"您点了:{dish}")
if kwargs:
print("具体要求:")
for key, value in kwargs.items():
print(f" {key}: {value}")
else:
print("没有具体要求")
# 调用函数时,通过关键词参数明确说明需求
order_dish_with_keywords("宫保鸡丁", spiciness="中辣", peanuts="多放")
# 输出:
# 您点了:宫保鸡丁
# 具体要求:
# spiciness: 中辣
# peanuts: 多放
# 不传关键词参数
order_dish_with_keywords("宫保鸡丁")
# 输出:
# 您点了:宫保鸡丁
# 没有具体要求
5. 传递参数的顺序:点菜的顺序
假设你点菜时可以有以下几种需求:
基本的菜品(位置参数)。
特殊的辣度要求(默认参数)。
额外的要求(不定参数)。
你必须按照这个顺序来点菜:
先告诉服务员你想要的基本菜品(位置参数)。
然后说明特殊的辣度要求(默认参数)。
最后提出额外的要求(不定参数)。
# 混合参数类型的函数 def order_complete_meal(dish1, dish2="红烧肉", *extras, **kwargs): # dish1 是位置参数,dish2 是默认参数,*extras 是不定参数,**kwargs 是关键词参数 print(f"您点了:{dish1} 和 {dish2}") if extras: print("额外要求:", ", ".join(extras)) if kwargs: print("具体要求:") for key, value in kwargs.items(): print(f" {key}: {value}") # 调用函数时,同时使用位置参数、默认参数、不定参数和关键词参数 order_complete_meal("宫保鸡丁", "红烧肉", "多放点花生", "少放点油", spiciness="中辣") # 输出: # 您点了:宫保鸡丁 和 红烧肉 # 额外要求: 多放点花生, 少放点油 # 具体要求: # spiciness: 中辣
比如:
正确的方式:“我要一份宫保鸡丁(位置参数),辣度是中辣(默认参数),多放点花生(不定参数)”。
错误的方式:“我要一份宫保鸡丁,多放点花生,辣度是中辣”(顺序混乱)。
总结
通过这个“餐厅点菜”的比喻,可以更形象地理解这些编程概念:
函数定义就像是菜单上的菜品,你可以通过点菜来享受服务。
局部变量就像是厨房里的食材,只在厨房里使用。
全局变量就像是餐厅里的调料和餐具,所有人都可以使用。
位置参数就像是按顺序点菜,顺序很重要。
作业:
题目1:计算圆的面积
- 任务: 编写一个名为 calculate_circle_area 的函数,该函数接收圆的半径 radius 作为参数,并返回圆的面积。圆的面积 = π * radius² (可以使用 math.pi 作为 π 的值)
- 要求:函数接收一个位置参数 radius。计算半径为5、0、-1时候的面积
- 注意点:可以采取try-except 使函数变得更加稳健,如果传入的半径为负数,函数应该返回 0 (或者可以考虑引发一个ValueError,但为了简单起见,先返回0)。
import math
def calculate_circle_area(radius):
try:
if radius < 0:
return 0
return math.pi * radius ** 2
except TypeError:
return 0
# 测试
print(calculate_circle_area(5)) # 正常情况
print(calculate_circle_area(0)) # 边界情况
print(calculate_circle_area(-1)) # 负数情况
print(calculate_circle_area("5")) # 非数字情况
题目2:计算矩形的面积
- 任务: 编写一个名为 calculate_rectangle_area 的函数,该函数接收矩形的长度 length 和宽度 width 作为参数,并返回矩形的面积。
- 公式: 矩形面积 = length * width
- 要求:函数接收两个位置参数 length 和 width。
- 函数返回计算得到的面积。
- 如果长度或宽度为负数,函数应该返回 0。
def calculate_rectangle_area(length, width):
try:
if length < 0 or width < 0:
return 0
return length * width
except TypeError:
return 0
# 测试
print(calculate_rectangle_area(10, 5)) # 正常情况
print(calculate_rectangle_area(-10, 5)) # 负数长度
print(calculate_rectangle_area(10, -5)) # 负数宽度
print(calculate_rectangle_area(-10, -5)) # 两个负数
print(calculate_rectangle_area(10, "5")) # 非数字宽度
题目3:计算任意数量数字的平均值
- 任务: 编写一个名为 calculate_average 的函数,该函数可以接收任意数量的数字作为参数(引入可变位置参数 (*args)),并返回它们的平均值。
- 要求:使用 *args 来接收所有传入的数字。
- 如果没有任何数字传入,函数应该返回 0。
- 函数返回计算得到的平均值。
def calculate_average(*args):
if not args:
return 0
return sum(args) / len(args)
# 测试
print(calculate_average(1, 2, 3, 4, 5)) # 正常情况
print(calculate_average()) # 无参数
print(calculate_average(10)) # 单个参数
题目4:打印用户信息
- 任务: 编写一个名为 print_user_info 的函数,该函数接收一个必需的参数 user_id,以及任意数量的额外用户信息(作为关键字参数)。
- 要求:
- user_id 是一个必需的位置参数。
- 使用 **kwargs 来接收额外的用户信息。
- 函数打印出用户ID,然后逐行打印所有提供的额外信息(键和值)。
- 函数不需要返回值
def print_user_info(user_id, **kwargs):
print(f"User ID: {user_id}")
for key, value in kwargs.items():
print(f"{key}: {value}")
# 测试
print_user_info(123, name="Alice", age=30, email="alice@example.com")
题目5:格式化几何图形描述
- 任务: 编写一个名为 describe_shape 的函数,该函数接收图形的名称 shape_name (必需),一个可选的 color (默认 “black”),以及任意数量的描述该图形尺寸的关键字参数 (例如 radius=5 对于圆,length=10, width=4 对于矩形)。
- 要求:shape_name 是必需的位置参数。
- color 是一个可选参数,默认值为 “black”。
- 使用 **kwargs 收集描述尺寸的参数。
- 函数返回一个描述字符串,格式如下:
- “A [color] [shape_name] with dimensions: [dim1_name]=[dim1_value], [dim2_name]=[dim2_value], …”如果 **kwargs 为空,则尺寸部分为 “with no specific dimensions.”
def describe_shape(shape_name, color="black", **kwargs): dimensions = ", ".join([f"{key}={value}" for key, value in kwargs.items()]) if dimensions: return f"A {color} {shape_name} with dimensions: {dimensions}" else: return f"A {color} {shape_name} with no specific dimensions." # 测试 print(describe_shape("circle", radius=5)) print(describe_shape("rectangle", color="red", length=10, width=5)) print(describe_shape("triangle", color="blue"))