6_Python函数:定义、调用与参数传递

Python函数:定义、调用与参数传递

函数是Python编程中的核心概念,它允许我们将代码组织成可重用的模块。本章将深入探讨Python函数的定义、调用、参数传递和返回值,以及一些高级函数特性。

函数基础

什么是函数?

函数是一组执行特定任务的代码块,它可以接收输入(参数),执行一系列操作,并返回结果。函数的主要目的是提高代码的模块化和可重用性。

函数的优势

  • 代码重用:避免重复编写相同的代码
  • 模块化设计:将复杂问题分解为更小的部分
  • 提高可读性:使代码结构更清晰
  • 易于维护:修改函数只需要在一个地方进行

函数定义与调用

定义函数

在Python中,使用def关键字定义函数:

def 函数名(参数1, 参数2, ...):
    """函数文档字符串(docstring):描述函数的功能"""
    # 函数体
    # 可以包含任意Python代码
    return 返回值  # 可选

例如,定义一个简单的求和函数:

def add_numbers(a, b):
    """返回两个数的和"""
    sum = a + b
    return sum

调用函数

定义函数后,可以通过函数名加括号来调用它,并传入所需的参数:

# 调用add_numbers函数
result = add_numbers(5, 3)
print(result)  # 输出: 8

# 直接打印函数调用的结果
print(add_numbers(10, 20))  # 输出: 30

函数文档字符串(Docstring)

函数文档字符串是放在函数定义后的第一行的字符串,用于描述函数的功能、参数和返回值。它可以帮助其他开发者理解函数的用途。

def calculate_area(radius):
    """
    计算圆的面积。
    
    参数:
        radius (float): 圆的半径
        
    返回:
        float: 圆的面积
    """
    return 3.14159 * radius ** 2

可以使用help()函数或直接访问函数的__doc__属性来查看文档字符串:

# 查看函数的文档字符串
help(calculate_area)

# 直接访问文档字符串
print(calculate_area.__doc__)

函数参数

Python支持多种参数传递方式,提供了灵活的函数定义方法。

位置参数

位置参数是最基本的参数形式,参数值根据定义顺序被传递:

def greet(name, message):
    """根据给定的名字和消息打印问候语"""
    print(f"{message}, {name}!")

# 调用函数时,参数按位置顺序传递
greet("张三", "早上好")  # 输出: 早上好, 张三!

关键字参数

关键字参数允许通过参数名来指定参数,无需按照定义的顺序传递:

def greet(name, message):
    print(f"{message}, {name}!")

# 使用关键字参数
greet(message="晚上好", name="李四")  # 输出: 晚上好, 李四!

默认参数

默认参数在定义函数时指定默认值,如果调用函数时未提供该参数的值,则使用默认值:

def greet(name, message="你好"):
    print(f"{message}, {name}!")

# 只提供必需的参数,使用默认消息
greet("王五")  # 输出: 你好, 王五!

# 提供所有参数,覆盖默认值
greet("赵六", "下午好")  # 输出: 下午好, 赵六!

重要提示:默认参数值在函数定义时计算一次,而不是在每次调用时重新计算。对于可变对象(如列表、字典),这可能导致意外行为:

# 错误示例:使用可变对象作为默认参数
def add_item(item, items=[]):  # 默认空列表在函数定义时创建一次
    items.append(item)
    return items

print(add_item("apple"))  # 输出: ['apple']
print(add_item("banana"))  # 输出: ['apple', 'banana'] - 可能不是预期结果!

# 正确做法
def add_item_correct(item, items=None):
    if items is None:
        items = []  # 每次调用都创建新的空列表
    items.append(item)
    return items

print(add_item_correct("apple"))  # 输出: ['apple']
print(add_item_correct("banana"))  # 输出: ['banana']

可变参数(*args)

可变参数允许函数接收任意数量的位置参数,这些参数被打包成一个元组:

def sum_all(*numbers):
    """计算所有传入参数的和"""
    total = 0
    for num in numbers:
        total += num
    return total

# 传递不同数量的参数
print(sum_all(1, 2))  # 输出: 3
print(sum_all(1, 2, 3, 4, 5))  # 输出: 15
print(sum_all())  # 输出: 0 (没有传参数)

关键字可变参数(**kwargs)

关键字可变参数允许函数接收任意数量的关键字参数,这些参数被打包成一个字典:

def print_info(**kwargs):
    """打印所有传入的关键字参数"""
    for key, value in kwargs.items():
        print(f"{key}: {value}")

# 传递不同的关键字参数
print_info(name="张三", age=25, city="北京")
# 输出:
# name: 张三
# age: 25
# city: 北京

混合使用不同类型的参数

在定义函数时,参数必须按照以下顺序:

  1. 位置参数
  2. 默认参数
  3. 可变参数 (*args)
  4. 关键字参数
  5. 关键字可变参数 (**kwargs)
def example_function(pos1, pos2, default1="默认值1", default2="默认值2", *args, key1, key2="值2", **kwargs):
    print(f"位置参数: {pos1}, {pos2}")
    print(f"默认参数: {default1}, {default2}")
    print(f"可变参数: {args}")
    print(f"关键字参数: {key1}, {key2}")
    print(f"关键字可变参数: {kwargs}")

# 调用混合了各种参数类型的函数
example_function(1, 2, "自定义1", *[10, 20, 30], key1="必须的关键字参数", extra1="额外1", extra2="额外2")

强制关键字参数

在Python 3中,可以使用*分隔符后的参数必须通过关键字指定,而不能通过位置传递:

def greet(name, *, message="你好"):
    print(f"{message}, {name}!")

# 正确调用
greet("张三", message="早上好")  # 输出: 早上好, 张三!

# 错误调用
# greet("张三", "早上好")  # 这会引发TypeError错误

函数返回值

基本返回值

函数可以使用return语句返回值:

def square(number):
    """返回数字的平方"""
    return number ** 2

result = square(4)
print(result)  # 输出: 16

返回多个值

Python函数可以同时返回多个值,这些值实际上被打包成一个元组:

def calculate_statistics(numbers):
    """计算一组数的和、平均值和最大值"""
    total = sum(numbers)
    average = total / len(numbers)
    maximum = max(numbers)
    return total, average, maximum

# 接收多个返回值
nums = [1, 2, 3, 4, 5]
sum_result, avg_result, max_result = calculate_statistics(nums)
print(f"总和: {sum_result}, 平均值: {avg_result}, 最大值: {max_result}")
# 输出: 总和: 15, 平均值: 3.0, 最大值: 5

# 也可以作为元组接收
stats = calculate_statistics(nums)
print(stats)  # 输出: (15, 3.0, 5)
print(type(stats))  # 输出: <class 'tuple'>

返回None

如果函数没有明确的return语句,或者只有return而没有返回值,则默认返回None

def greet(name):
    print(f"你好, {name}!")
    # 没有return语句

result = greet("张三")  # 打印: 你好, 张三!
print(result)  # 输出: None

def early_return(x):
    if x < 0:
        return  # 提前返回,没有返回值
    print(f"x是非负数: {x}")

early_return(-5)  # 什么都不打印
early_return(10)  # 打印: x是非负数: 10

变量作用域和命名空间

局部作用域和全局作用域

Python中的变量有不同的作用域(可见范围):

  1. 局部作用域:在函数内部定义的变量,只在函数内部可见
  2. 全局作用域:在函数外部定义的变量,可以在整个模块中访问
# 全局变量
global_var = "我是全局变量"

def function_demo():
    # 局部变量
    local_var = "我是局部变量"
    print(global_var)  # 可以访问全局变量
    print(local_var)  # 可以访问局部变量

function_demo()
print(global_var)  # 可以访问全局变量
# print(local_var)  # 错误:local_var不在全局作用域中

global和nonlocal关键字

如果需要在函数内部修改全局变量,需要使用global关键字:

counter = 0

def increment():
    global counter  # 声明counter是全局变量
    counter += 1
    print(f"计数器: {counter}")

increment()  # 输出: 计数器: 1
increment()  # 输出: 计数器: 2
print(counter)  # 输出: 2

nonlocal关键字用于在嵌套函数中修改外层函数的变量:

def outer_function():
    outer_var = "外层变量"
    
    def inner_function():
        nonlocal outer_var  # 声明outer_var是外层函数的变量
        outer_var = "修改后的外层变量"
        print(f"内层函数: {outer_var}")
    
    print(f"调用前: {outer_var}")
    inner_function()
    print(f"调用后: {outer_var}")

outer_function()
# 输出:
# 调用前: 外层变量
# 内层函数: 修改后的外层变量
# 调用后: 修改后的外层变量

高级函数特性

匿名函数(Lambda)

Lambda函数是一种简单的、单行的、匿名函数,使用lambda关键字定义:

# 普通函数
def square(x):
    return x ** 2

# 等价的lambda函数
square_lambda = lambda x: x ** 2

print(square(5))       # 输出: 25
print(square_lambda(5))  # 输出: 25

# lambda函数通常用于需要函数对象的场合
numbers = [1, 5, 3, 9, 2, 6]
sorted_numbers = sorted(numbers, key=lambda x: abs(x - 5))
print(sorted_numbers)  # 输出按与5的差值排序的结果: [5, 6, 3, 9, 2, 1]

Lambda函数最适合用于简单的单行表达式,对于复杂逻辑应该使用常规函数。

函数作为参数

在Python中,函数是一等公民,可以作为参数传递:

def apply_operation(x, y, operation):
    """应用给定的操作函数到x和y上"""
    return operation(x, y)

def add(a, b):
    return a + b

def multiply(a, b):
    return a * b

# 传递函数作为参数
result1 = apply_operation(5, 3, add)
print(result1)  # 输出: 8

result2 = apply_operation(5, 3, multiply)
print(result2)  # 输出: 15

# 使用lambda表达式
result3 = apply_operation(5, 3, lambda a, b: a - b)
print(result3)  # 输出: 2

闭包(Closure)

闭包是一个函数,它记住了创建它的环境中的变量,即使那些变量的作用域已经结束:

def create_multiplier(factor):
    """创建一个乘以指定因子的函数"""
    def multiplier(x):
        return x * factor  # 使用外部函数的变量factor
    return multiplier  # 返回内部函数

# 创建乘以2和乘以5的函数
double = create_multiplier(2)
quintuple = create_multiplier(5)

print(double(7))     # 输出: 14
print(quintuple(7))  # 输出: 35

闭包常用于创建工厂函数、回调等场景。

递归函数

递归函数是调用自身的函数。在使用递归时,必须定义一个终止条件以避免无限递归:

def factorial(n):
    """计算n的阶乘"""
    # 基本情况(终止条件)
    if n == 0 or n == 1:
        return 1
    # 递归调用
    else:
        return n * factorial(n - 1)

print(factorial(5))  # 输出: 120 (5 * 4 * 3 * 2 * 1)

递归函数适合解决能够分解为子问题的问题,如树遍历、分治算法等。但要注意Python的递归深度限制(默认为1000)。

内置函数

Python提供了许多有用的内置函数,以下是一些常用的例子:

map(), filter(), reduce()

这些函数接受一个函数和一个或多个可迭代对象作为参数,用于数据转换和处理:

# map() - 将函数应用于可迭代对象的每个元素
numbers = [1, 2, 3, 4, 5]
squared = list(map(lambda x: x**2, numbers))
print(squared)  # 输出: [1, 4, 9, 16, 25]

# filter() - 筛选符合条件的元素
even_numbers = list(filter(lambda x: x % 2 == 0, numbers))
print(even_numbers)  # 输出: [2, 4]

# reduce() - 累积应用函数到序列的元素
from functools import reduce
product = reduce(lambda x, y: x * y, numbers)
print(product)  # 输出: 120 (1 * 2 * 3 * 4 * 5)

zip()

zip()函数将多个可迭代对象的元素配对:

names = ["Alice", "Bob", "Charlie"]
ages = [25, 30, 35]
cities = ["New York", "London", "Paris"]

# 将三个列表"压缩"在一起
combined = list(zip(names, ages, cities))
print(combined)
# 输出: [('Alice', 25, 'New York'), ('Bob', 30, 'London'), ('Charlie', 35, 'Paris')]

# 解压缩
unzipped_names, unzipped_ages, unzipped_cities = zip(*combined)
print(unzipped_names)  # 输出: ('Alice', 'Bob', 'Charlie')

enumerate()

enumerate()函数将一个可计数的对象组合为一个索引序列:

fruits = ["苹果", "香蕉", "橙子"]

# 使用enumerate获取索引和值
for index, fruit in enumerate(fruits):
    print(f"索引 {index}: {fruit}")
# 输出:
# 索引 0: 苹果
# 索引 1: 香蕉
# 索引 2: 橙子

# 从指定索引开始
for index, fruit in enumerate(fruits, start=1):
    print(f"第 {index} 个水果: {fruit}")
# 输出:
# 第 1 个水果: 苹果
# 第 2 个水果: 香蕉
# 第 3 个水果: 橙子

编程实践

用函数解决实际问题

让我们看一些使用函数解决实际问题的例子:

示例1:温度转换器
def celsius_to_fahrenheit(celsius):
    """将摄氏温度转换为华氏温度"""
    return (celsius * 9/5) + 32

def fahrenheit_to_celsius(fahrenheit):
    """将华氏温度转换为摄氏温度"""
    return (fahrenheit - 32) * 5/9

# 测试温度转换函数
celsius_temp = 25
fahrenheit_temp = celsius_to_fahrenheit(celsius_temp)
print(f"{celsius_temp}°C = {fahrenheit_temp:.2f}°F")

fahrenheit_temp = 98.6
celsius_temp = fahrenheit_to_celsius(fahrenheit_temp)
print(f"{fahrenheit_temp}°F = {celsius_temp:.2f}°C")
示例2:密码检查器
def is_strong_password(password):
    """
    检查密码是否强壮
    
    强密码的标准:
    - 至少8个字符
    - 包含至少一个数字
    - 包含至少一个大写字母
    - 包含至少一个小写字母
    - 包含至少一个特殊字符
    """
    if len(password) < 8:
        return False
    
    has_digit = False
    has_upper = False
    has_lower = False
    has_special = False
    special_chars = "!@#$%^&*()-+?_=,<>/"
    
    for char in password:
        if char.isdigit():
            has_digit = True
        elif char.isupper():
            has_upper = True
        elif char.islower():
            has_lower = True
        elif char in special_chars:
            has_special = True
    
    return has_digit and has_upper and has_lower and has_special

# 测试密码强度检查器
passwords = ["password", "Password1", "P@ssw0rd", "12345", "P@ssw0rd!"]
for pwd in passwords:
    if is_strong_password(pwd):
        print(f"'{pwd}' 是一个强密码")
    else:
        print(f"'{pwd}' 不是强密码")

编程练习

为了巩固本章所学内容,尝试完成以下练习:

  1. 编写一个函数,接受一个正整数n作为参数,返回1到n的所有素数。
  2. 创建一个函数,接受一个字符串,返回这个字符串中单词的数量。
  3. 编写一个函数,接受任意数量的数字,返回这些数字的平均值。
  4. 创建一个计算器函数,能够根据操作符(+, -, *, /)执行两个数的运算。
  5. 实现一个递归函数来计算斐波那契数列的第n项(F(0) = 0, F(1) = 1, F(n) = F(n-1) + F(n-2))。

小结

本章我们学习了Python函数的多个方面:

  • 函数的定义与调用
  • 不同类型的参数(位置参数、关键字参数、默认参数、可变参数等)
  • 函数的返回值
  • 变量作用域和命名空间
  • 高级函数特性(lambda函数、函数作为参数、闭包、递归函数)
  • 有用的内置函数和实际应用示例

函数是Python编程的基本构建块,也是代码复用和模块化的关键。掌握函数的使用将使你能够编写更简洁、更可维护的代码。在下一章中,我们将学习Python的模块和包,了解如何组织更大规模的Python程序。

Python实现的CNN卷积神经网络手写数字识别项目代码+代码注释和数据集(毕业设计&期末大作业),个人经导师指导并认可通过的高分设计项目,评审分98分,项目中的源码都是经过本地编译过可运行的,都经过严格调试,确保可以运行!主要针对计算机相关专业的正在做大作业、毕业设计的生和需要项目实战练习的习者,资源项目的难度比较适中,内容都是经过助教老师审定过的能够满足习、使用需求,如果有需要的话可以放心下载使用。 Python实现的CNN卷积神经网络手写数字识别项目代码+代码注释和数据集(毕业设计&期末大作业)Python实现的CNN卷积神经网络手写数字识别项目代码+代码注释和数据集(毕业设计&期末大作业)Python实现的CNN卷积神经网络手写数字识别项目代码+代码注释和数据集(毕业设计&期末大作业)Python实现的CNN卷积神经网络手写数字识别项目代码+代码注释和数据集(毕业设计&期末大作业)Python实现的CNN卷积神经网络手写数字识别项目代码+代码注释和数据集(毕业设计&期末大作业)Python实现的CNN卷积神经网络手写数字识别项目代码+代码注释和数据集(毕业设计&期末大作业)Python实现的CNN卷积神经网络手写数字识别项目代码+代码注释和数据集(毕业设计&期末大作业)Python实现的CNN卷积神经网络手写数字识别项目代码+代码注释和数据集(毕业设计&期末大作业)Python实现的CNN卷积神经网络手写数字识别项目代码+代码注释和数据集(毕业设计&期末大作业)Python实现的CNN卷积神经网络手写数字识别项目代码+代码注释和数据集(毕业设计&期末大作业)Python实现的CNN卷积神经网络手写数字识别项目代码+代码注释和数据集(毕业设计&期末大作业)Python实现的CNN卷积神经网络手写数字识别项目代码+代码注释和数据集(毕业设计&期末大作业)Pyth
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值