Python-Basic Day-4 函数-基础知识

一、为什么需要函数?

  • 代码复用:写一次,用无数次。
  • 模块化:将复杂问题分解为小的、可管理的部分。
  • 易于维护:修改一个功能,只需修改对应的函数。
  • 提高可读性:好的函数名本身就是一种注释。

二、函数参数

函数大家应该都会,就不从头细讲了,说一些容易忽略的点

2.1 位置参数和关键字参数

python 复制代码
def describe_person(name, age, city): 
"""描述一个人的信息""" 
print(f"姓名: {name}, 年龄: {age}, 城市: {city}")

# 混合使用:位置参数必须在关键字参数之前
describe_person("王五", city="广州", age=28) # 输出: 姓名: 王五, 年龄: 28, 城市: 广州
describe_person(name="王五", 28, city="广州") # 这会报错!

2.2 重要陷阱:可变默认参数

永远不要将可变对象(如列表、字典)作为默认参数!

python 复制代码
# 错误示范 - 可变默认参数
def add_item_to_list(item, my_list=[]):
    """向列表中添加一个项目(错误示范)。"""
    my_list.append(item)
    return my_list

print(add_item_to_list(1)) # 输出: [1]
print(add_item_to_list(2)) # 输出: [1, 2]  <- 意想不到!我们期望的是 [2]
print(add_item_to_list(3)) # 输出: [1, 2, 3] <- 问题持续恶化

原因: 默认参数 my_list=[] 在函数定义时只被创建一次 。后续所有调用,如果不提供 my_list,都会使用同一个列表对象。

正确做法: 使用 None 作为默认值,然后在函数内部创建新对象。

python 复制代码
# 代码 2.4: 正确示范
def add_item_to_list_correctly(item, my_list=None):
    """向列表中添加一个项目(正确示范)。"""
    if my_list is None:
        my_list = []  # 每次调用都创建一个新的列表
    my_list.append(item)
    return my_list

print(add_item_to_list_correctly(1)) # 输出: [1]
print(add_item_to_list_correctly(2)) # 输出: [2]
print(add_item_to_list_correctly(3)) # 输出: [3]

2.3 可变长度参数

当不确定会传递多少个参数时,可变长度参数就派上用场了。

  • *args:接收任意数量的位置 参数,它们被组装成一个元组
  • **kwargs:接收任意数量的关键字 参数,它们被组装成一个字典
python 复制代码
# *args 和 **kwargs
def log_message(*args, **kwargs):
    """记录任意数量的消息和配置信息。"""
    print("--- 位置参数 ---")
    for arg in args:
        print(f"- {arg}")
    
    print("\n--- 关键字参数 ---")
    for key, value in kwargs.items():
        print(f"- {key}: {value}")

log_message("系统启动", "加载模块", level="INFO", user="admin")

2.4 参数解包

2.4.1 函数定义与参数

python 复制代码
def introduce(name, age, city):
    print(f"我叫{name},今年{age}岁,来自{city}。")

2.4.2 列表/元组解包 (*args)

接下来,我们看这段代码:

python 复制代码
args = ["李四", 28, "广州"]  # args 是一个列表
introduce(*args)            # 使用 * 解包列表
  • args 是一个列表 (或者也可以是元组),它包含了三个元素:"李四"28"广州"
  • introduce(*args) 中的 *解包操作符
  • *args 的作用是把列表 args 解开 ,把里面的元素依次 作为位置参数传递给 introduce 函数。
  • 所以,introduce(*args) 这行代码,等价于 introduce("李四", 28, "广州")
  • 这样就成功地把列表里的数据传递给了函数,而不需要手动写三个参数。

2.4.3 字典解包 (**kwargs)

最后,我们看这段代码:

python 复制代码
kwargs = {"name": "王五", "age": 32, "city": "深圳"}  # kwargs 是一个字典
introduce(**kwargs)                                   # 使用 ** 解包字典
  • kwargs 是一个字典 。它的 (key)分别是 name, age, city,这正好与 introduce 函数的参数名完全一致。
  • introduce(**kwargs) 中的 **字典解包操作符
  • **kwargs 的作用是把字典 kwargs 解开 ,把里面的键值对 作为关键字参数 (keyword arguments)传递给 introduce 函数。
  • 所以,introduce(**kwargs) 这行代码,等价于 introduce(name="王五", age=32, city="深圳")
  • 同样,这也成功地把字典里的数据传递给了函数。

总结

  • 普通调用introduce("张三", 25, "北京") - 直接传入三个值。
  • 列表/元组解包 (*) :当数据存储在一个序列 (如列表或元组)中,并且顺序与函数参数顺序一致 时,可以使用 * 来解包,方便地将序列中的元素作为位置参数传递。
  • 字典解包 (**) :当数据存储在一个字典 中,并且字典的键与函数参数名一致 时,可以使用 ** 来解包,方便地将字典中的键值对作为关键字参数传递。

这两种解包方式在处理动态数据或使代码更简洁时非常有用!

三、返回值

3.1 返回多个值

python 复制代码
def calculate(a, b):
    """返回多个值(实际上是返回元组)"""
    sum_result = a + b
    difference = a - b
    product = a * b
    quotient = a / b if b != 0 else None
    return sum_result, difference, product, quotient

result = calculate(10, 5)
print(result)  # 输出: (15, 5, 50, 2.0)

# 解包多个返回值
sum_val, diff_val, prod_val, quot_val = calculate(8, 4)
print(f"和: {sum_val}, 差: {diff_val}, 积: {prod_val}, 商: {quot_val}")

在 Python 中,当在 return 语句后面用逗号 , 分隔多个值时,Python 会自动将它们打包成一个元组(tuple) 再返回。

所以,return sum_result, difference, product, quotient这行代码等价于

python 复制代码
return (sum_result, difference, product, quotient)

括号 () 是可选的,不写括号 Python 也会创建元组。

四、匿名函数

lambda 函数是一种匿名函数 (anonymous function)。它是一种非常简洁的创建简单函数 的方式,通常用于需要一个一次性、简单 的函数,而不想正式定义一个完整函数(使用 def)的场合。

4.1 lambda 函数的基本语法

python 复制代码
lambda 参数1, 参数2, ... : 表达式
  • lambda:定义匿名函数的关键字。
  • 参数1, 参数2, ...:函数接收的参数,可以没有,也可以有一个或多个。
  • ::分隔参数和函数体。
  • 表达式一个 表达式,lambda 函数会自动返回这个表达式的结果注意:这里不能是语句 (如 print, for, while 等),只能是一个计算结果的表达式。

4.2 lambda 函数 vs 普通函数 (def)

普通函数 (def)

python 复制代码
def add(x, y):
    return x + y

result = add(3, 5)
print(result)  # 输出: 8

lambda 函数

python 复制代码
# 创建一个 lambda 函数,并将其赋值给变量 add
add = lambda x, y: x + y

result = add(3, 5)
print(result)  # 输出: 8
  • 我们将这个匿名函数赋值给了变量 add,然后就可以像普通函数一样调用它了。

4.3 排序中的应用

python 复制代码
students = [("Alice", 88), ("Bob", 95), ("Charlie", 78)]

# 按照元组的第二个元素(成绩)进行排序
sorted_by_grade = sorted(students, key=lambda student: student[1])

print(sorted_by_grade)  # 输出: [('Charlie', 78), ('Alice', 88), ('Bob', 95)]

sorted() 是 Python 的一个内置函数,它的作用是对一个可迭代对象(如列表)进行排序,并返回一个新的、已排序的列表

它的基本语法是:

ini 复制代码
sorted(要排序的列表, key=一个函数)
  • 要排序的列表:在这里就是 students
  • key=:这是一个关键字参数 。它的值是一个函数 。这个函数告诉 sorted 应该按照什么规则来排序

五、作用域

5.1 局部作用域

python 复制代码
def my_function():
    local_var = "我是局部变量"
    print(local_var)  # 在函数内部可以访问

my_function()
# print(local_var)  # 报错: NameError,在函数外部无法访问局部变量

5.2 全局作用域

python 复制代码
global_var = "我是全局变量"

def access_global():
    """访问全局变量"""
    print(global_var)  # 可以读取全局变量

def modify_global():
    """修改全局变量"""
    global global_var  # 使用global关键字声明
    global_var = "全局变量已被修改"

access_global()  # 输出: 我是全局变量
modify_global()
access_global()  # 输出: 全局变量已被修改

当 Python 在函数内部遇到 variable_name = value 这样的赋值语句时,它会默认 认为你想要创建一个局部变量 variable_name

使用 global 关键字

  • global global_var 这一行代码告诉 Python

    • "嘿,Python,我在函数内部要使用的 global_var不是 一个新的局部变量,而是那个在全局作用域 下定义的 global_var。"
    • "当我对 global_var 进行赋值时,请直接修改全局 的那个 global_var。"
  • 因此,global_var = "全局变量已被修改" 这行代码现在的作用是:

    • 修改 全局作用域下的 global_var 变量的值。

5.3 嵌套函数与非局部变量

python 复制代码
def outer_function():
    outer_var = 1
    
    def inner_function():
        nonlocal outer_var  # 使用nonlocal关键字
        outer_var = 2
        inner_var = 3
        print(f"内部函数: {outer_var}")
    
    inner_function()
    print(f"外部函数: {outer_var}")
    # print(inner_var)  # 报错: 无法访问内部函数的变量

outer_function()

5.4 闭包

python 复制代码
def make_multiplier(factor):
    """创建乘法器函数"""
    def multiplier(x):
        return x * factor
    return multiplier

double = make_multiplier(2)
triple = make_multiplier(3)

print(double(5))  # 输出: 10
print(triple(5))  # 输出: 15

闭包(Closure)的概念

当内部函数 multiplier 记住了它外部的变量 factor(即使 make_multiplier 已经运行结束),我们就说 multiplier 函数形成了一个闭包

  • 闭包 = 函数 + 函数定义时的环境(变量)
  • multiplier 不仅是一个函数,它还"封闭"了 factor 这个变量。

这种模式叫做工厂模式函数工厂,它有很多用途,具体用途略~

相关推荐
FreeCode2 小时前
LangSmith Studio 调试智能体
python·langchain·agent
Paraverse_徐志斌2 小时前
基于 PyTorch + BERT 意图识别与模型微调
人工智能·pytorch·python·bert·transformer
wtrees_松阳2 小时前
Flask数据加密实战:医疗系统安全指南
开发语言·python
数据知道2 小时前
FastAPI项目:构建打字速度测试网站(MySQL版本)
数据库·python·mysql·fastapi·python项目
vvoennvv2 小时前
【Python TensorFlow】CNN-BiLSTM-Attention时序预测 卷积神经网络-双向长短期记忆神经网络组合模型带注意力机制(附代码)
python·神经网络·cnn·tensorflow·lstm·bilstm·注意力
程序员爱钓鱼3 小时前
Python 编程实战:环境管理与依赖管理(venv / Poetry)
后端·python·trae
程序员爱钓鱼3 小时前
Python 编程实战 :打包与发布(PyInstaller / pip 包发布)
后端·python·trae
我叫侯小科3 小时前
PyTorch 实战:手写数字识别(MNIST)从入门到精通
人工智能·pytorch·python
青衫客363 小时前
浅谈 Python 的 C3 线性化算法(C3 Linearization):多继承背后的秩序之美
python·mro·c3线性化算法