python 训练 Day 26 函数专题1:函数定义与参数

函数的基本写法:

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 语句(例如在不同的条件分支中)。

不带参数的函数

# 定义一个简单的问候函数
def greet(): #打印一句问候语
    message = "大家好!欢迎学习Python函数定义!"
    print(message)

greet()

带参数的函数

- Parameters (形参): 在函数定义中列出的变量名 (如 name, feature1, feature2)。
- Arguments (实参): 在函数调用时传递给函数的实际值 (如 "张三", 10, 25),也就是实际的数值(实参)传给了 形参(定义时候的变量)

注意点: 定义的时候把函数的参数称之为形参,调用的时候把函数的参数称之为实参。

# 定义一个带一个参数的问候函数
def greet_person(name):
    """根据给定的名字打印问候语。

    Args:
        name (str): 要问候的人的名字。
    """
    message = f"你好, {name}! 很高兴认识你。"
    print(message)

greet_person("张三")  # 输出: 你好, 张三! 很高兴认识你。

name为形参,“张三”为实参

# 定义一个带多个参数的函数 (例如,在机器学习中计算两个特征的和)
def add_features(feature1, feature2):
    """计算两个数值特征的和。
    Args:
        feature1 (float or int): 第一个特征值。
        feature2 (float or int): 第二个特征值。
    """
    total = feature1 + feature2
    print(f"{feature1} + {feature2} = {total}")

add_features(10, 25)       # 输出: 10 + 25 = 35

带返回值的参数

# 定义一个计算和并返回结果的函数
def calculate_sum(a, b):
    """计算两个数的和并返回结果。

    Args:
        a (float or int): 第一个数。
        b (float or int): 第二个数。

    Returns:
        float or int: 两个数的和。
    """
    result = a + b
    return result / print(result)

calculate_sum(2, 3)
# 函数可以返回多种类型的数据,包括列表、字典等
# 例如,在数据预处理中,一个函数可能返回处理后的特征列表
def preprocess_data(raw_data_points):
    """模拟数据预处理,例如将所有数据点乘以2。

    Args:
        raw_data_points (list): 原始数据点列表。

    Returns:
        list: 处理后的数据点列表。
    """
    processed = []
    for point in raw_data_points:
        processed.append(point * 2) # 假设预处理是乘以2
    return processed

data = [1, 2, 3, 4, 5]
processed_data = preprocess_data(data)

print(f"原始数据: {data}")
print(f"预处理后数据: {processed_data}") # 输出: [2, 4, 6, 8, 10]

变量作用域

理解变量在何处可见和可访问非常重要。

- 局部变量 (Local Variables): 在函数内部定义的变量,只在该函数内部有效。当函数执行完毕后,局部变量通常会被销毁。

- 全局变量 (Global Variables): 在所有函数外部定义的变量,可以在程序的任何地方被访问(但在函数内部修改全局变量需要特殊声明,如 global 关键字,初学阶段可以先避免)。

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 只在函数内存在

函数的参数类型

参数有以下类型:
- 位置参数 (Positional Arguments): 调用时按顺序匹配。
- 默认参数值 (Default Parameter Values): 定义函数时给参数指定默认值,调用时如果未提供该参数,则使用默认值。
- 可变数量参数 (*args 和 **kwargs):
    - *args: 将多余的位置参数收集为一个元组。
    - **kwargs: 将多余的关键字参数收集为一个字典。
  
关键字参数 (Keyword Arguments)并非是一种参数,而是一种传递参数的手段: 调用时通过 参数名=值 的形式指定,可以不按顺序。他可以传位置参数的值,也可以传默认参数的值,也可以传可变参数的值,也可以传关键字参数的值。为了可读性,更推荐对所有参数均采取关键字参数传递。

#位置参数
def describe_pet(animal_type, pet_name):
    """显示宠物的信息。"""
    print(f"\n我有一只 {animal_type}.")
    print(f"我的 {animal_type} 的名字叫 {pet_name.title()}.")

describe_pet("猫", "咪咪") # 使用关键字参数,顺序不重要

为了可读性,更推荐对所有参数采取关键词参数的写法

假设一个复杂的绘图函数
plot_data(data, x_col, y_col, "blue", "-", True, False, "My Plot", "X-axis", "Y-axis") # 不清晰

#关键字参数
plot_data(data=my_data, x_column='time', y_column='value',
          color='blue', linestyle='-', show_grid=True, use_log_scale=False,
          title="My Awesome Plot", xlabel="Time (s)", ylabel="Value") # 非常清晰

当一个函数有很多参数时,如果只用位置参数,调用者可能需要反复查看函数定义才能确定每个参数的含义。使用关键字参数,每个值的含义都通过其前面的参数名清晰地标示出来。

describe_pet(animal_type="猫", pet_name="咪咪") # 使用关键字参数,顺序不重要
describe_pet(pet_name="旺财", animal_type="狗") # 顺序改变,但结果正确

默认参数

def describe_pet_default(pet_name, animal_type="狗"): # animal_type 有默认值
    """显示宠物的信息,动物类型默认为狗。"""
    print(f"我有一只 {animal_type}.")
    print(f"我的 {animal_type} 的名字叫 {pet_name.title()}.")

describe_pet_default(pet_name="小黑") # animal_type 使用默认值 "狗"
describe_pet_default(pet_name="雪球", animal_type="仓鼠") # 提供 animal_type,覆盖默认值
# 注意:带默认值的参数必须放在没有默认值的参数之后

*args收集多余位置参数

当函数被调用时,Python 会先尝试用调用时提供的位置参数去填充函数定义中所有明确定义的、非关键字的形参 (也就是那些普通的,没有 * 或 ** 前缀的参数,包括有默认值的和没有默认值的)。
如果在填充完所有这些明确定义的形参后,调用时还有剩余的位置参数,那么这些“多余的”位置参数就会被收集起来,形成一个元组 (tuple),并赋值给 *args 指定的那个变量(通常就是 args)。
如果调用时提供的位置参数数量正好等于或少于明确定义的形参数量(且满足了所有必需参数),那么 *args 就会是一个空元组 ()。

def make_pizza(size, *toppings):
    """概述要制作的比萨。
    *toppings 会将所有额外的位置参数收集到一个元组中。
    """
    print(f"\n制作一个 {size} 寸的比萨,配料如下:")
    if toppings: # 只要toppings不为空元组,就会执行
        for topping in toppings:
            print(f"- {topping}")
    else:
        print("- 原味 (无额外配料)")

make_pizza(12, "蘑菇")
make_pizza(16, "香肠", "青椒", "洋葱")
make_pizza(9) # toppings 会是空元组

**kwargs收集多余关键词参数

当函数被调用时,Python 会先处理完所有的位置参数(包括填充明确定义的形参和收集到 *args 中)。
然后,Python 会看调用时提供的关键字参数 (形如 name=value)。它会尝试用这些关键字参数去填充函数定义中所有与关键字同名的、明确定义的形参(这些形参可能之前没有被位置参数填充)。

如果在填充完所有能通过名字匹配上的明确定义的形参后,调用时还有剩余的关键字参数(即这些关键字参数的名字在函数定义中没有对应的明确形参名),那么这些“多余的”关键字参数就会被收集起来,形成一个字典 (dictionary),并赋值给 **kwargs 指定的那个变量(通常就是 kwargs)。

如果调用时提供的所有关键字参数都能在函数定义中找到对应的明确形参名,那么 **kwargs 就会是一个空字典 {}。

def build_profile(first_name, last_name, **user_info):
    """创建一个字典,其中包含我们知道的有关用户的一切。
    **user_info 会将所有额外的关键字参数收集到一个字典中。
    """
    profile = {}
    profile['first_name'] = first_name
    profile['last_name'] = last_name
    for key, value in user_info.items():
        profile[key] = value
    return profile

user_profile = build_profile('爱因斯坦', '阿尔伯特',
                             location='普林斯顿',
                             field='物理学',
                             hobby='小提琴')
print(f"\n用户信息: {user_profile}")
# 输出: {'first_name': '爱因斯坦', 'last_name': '阿尔伯特', 'location': '普林斯顿', 'field': '物理学', 'hobby': '小提琴'}

*args 和 **kwargs 的核心目的是让函数能够接收不定数量的参数,并以元组和字典的形式在函数内部进行处理。

也就是说 当位置参数用完了 就自动变成*args,当关键词参数用完了 就自动变成**kwarges

# 同时出现 *args 和 **kwargs,注意参数的传入顺序
def process_data(id_num, name, *tags, status="pending", **details): # 注意,这里的status 是仅关键字参数,必须通过关键词传值
    print(f"ID: {id_num}")
    print(f"Name: {name}")
    print(f"Tags (*args): {tags}")
    print(f"Status: {status}")          # status 是一个有默认值的普通关键字参数
    print(f"Details (**kwargs): {details}")
    print("-" * 20)

# 调用1:
process_data(101, "Alice", "vip", "new_user", location="USA", age=30)
# ID: 101
# Name: Alice
# Tags (*args): ('vip', 'new_user')  <-- "vip", "new_user" 是多余的位置参数,被 *tags 收集
# Status: pending                    <-- status 使用默认值,因为调用中没有 status=...
# Details (**kwargs): {'location': 'USA', 'age': 30} <-- location 和 age 是多余的关键字参数,被 **details 收集
# --------------------

# 调用2:
process_data(102, "Bob", status="active", department="Sales")
# ID: 102
# Name: Bob
# Tags (*args): ()                   <-- 没有多余的位置参数
# Status: active                     <-- status 被关键字参数 'active' 覆盖
# Details (**kwargs): {'department': 'Sales'} <-- department 是多余的关键字参数
# --------------------

# 调用3:
process_data(103, "Charlie", "admin") # 'admin' 会被 *tags 捕获
# ID: 103
# Name: Charlie
# Tags (*args): ('admin',)
# Status: pending
# Details (**kwargs): {}
# --------------------

# 调用4: (演示关键字参数也可以用于定义中的位置参数)
process_data(name="David", id_num=104, profession="Engineer")
# ID: 104
# Name: David
# Tags (*args): ()
# Status: pending
# Details (**kwargs): {'profession': 'Engineer'}
# --------------------
题目1:计算圆的面积

● 任务: 编写一个名为 calculate_circle_area 的函数,该函数接收圆的半径 radius 作为参数,并返回圆的面积。圆的面积 = π * radius² (可以使用 math.pi 作为 π 的值)

● 要求:函数接收一个位置参数 radius。计算半径为5、0、-1时候的面积

● 注意点:可以采取try-except 使函数变得更加稳健,如果传入的半径为负数,函数应该返回 0 (或者可以考虑引发一个ValueError,但为了简单起见,先返回0)。

import math


def calculate_circle_area(radius):
    if radius < 0:
        return 0
    else:
        return math.pi * (radius ** 2)


print(f'Radius 5: {calculate_circle_area(5)}')
print(f'Radius 0: {calculate_circle_area(0)}')
print(f'Radius -1: {calculate_circle_area(-1)}')

题目2:计算矩形的面积

● 任务: 编写一个名为 calculate_rectangle_area 的函数,该函数接收矩形的长度 length 和宽度 width 作为参数,并返回矩形的面积。

● 公式: 矩形面积 = length * width

● 要求:函数接收两个位置参数 length 和 width。

○ 函数返回计算得到的面积。

○ 如果长度或宽度为负数,函数应该返回 0。

def calculate_rectangle_area(length,width)

if length*width<0:
 n=0
else:
 n=length*width
 
return n

题目3:计算任意数量数字的平均值

● 任务: 编写一个名为 calculate_average 的函数,该函数可以接收任意数量的数字作为参数(引入可变位置参数 (*args)),并返回它们的平均值。

● 要求:使用 *args 来接收所有传入的数字。

○ 如果没有任何数字传入,函数应该返回 0。

○ 函数返回计算得到的平均值。

def calculate_average(*args)
if not args:
  return 0
else:
  return sum(args) / len(args)

print(f'Average of 1, 2, 3, 4, 5: {calculate_average(1, 2, 3, 4, 5)}')
print(f'Average of no numbers: {calculate_average()}')

题目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(114514, name='野兽先辈', city='下北泽')

题目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):
    description = f'A {color} {shape_name}'
    if not kwargs:
        description += ' with no specific dimensions.'
    else:
        dimensions = []
        for key, value in kwargs.items():
            dimensions.append(f'{key}={value}')
        description += ' with dimensions: ' + ', '.join(dimensions)
    return description


print(describe_shape('circle', radius=5, color='red'))
print(describe_shape('rectangle', length=10, width=4))
print(describe_shape('triangle', base=6, height=8, color='blue'))
print(describe_shape('point', color='green'))

@浙大疏锦行

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值