Python训练营打卡 Day26

发布于:2025-05-16 ⋅ 阅读:(10) ⋅ 点赞:(0)

 函数专题1

知识点回顾:

  1. 函数的定义
  2. 变量作用域:局部变量和全局变量
  3. 函数的参数类型:位置参数、默认参数、不定参数
  4. 传递参数的手段:关键词参数
  5. 传递参数的顺序:同时出现三种参数类型时

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. 传递参数的顺序:点菜的顺序

假设你点菜时可以有以下几种需求:

  1. 基本的菜品(位置参数)。

  2. 特殊的辣度要求(默认参数)。

  3. 额外的要求(不定参数)。

你必须按照这个顺序来点菜:

  1. 先告诉服务员你想要的基本菜品(位置参数)。

  2. 然后说明特殊的辣度要求(默认参数)。

  3. 最后提出额外的要求(不定参数)。

  4. # 混合参数类型的函数
    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"))