六、函数解析

函数是Python编程的核心概念之一,它允许我们将代码封装为可重用的模块,提高代码的可读性、可维护性和复用性。本文将系统介绍Python函数的定义、参数传递、作用域、装饰器等关键概念,并通过丰富示例展示其实际应用。

文章目录

  • 一、函数基础:定义与调用

    • 1、基本语法结构
    • 2、最简单的函数示例
    • 3、带参数的函数
    • 4、返回值的使用
  • 二、参数传递机制详解

    • 1、位置参数与关键字参数
    • 2、默认参数
    • 3、可变参数 (*args)
    • 4、关键字可变参数 (**kwargs)
    • 5、参数解包示例
  • 三、函数作用域与生命周期

    • 1、变量作用域规则
    • 2、global关键字
    • 3、nonlocal关键字(嵌套函数中使用)
  • 四、高阶函数与函数式编程

    • 1、函数作为参数传递
    • 2、函数作为返回值(闭包)
    • 3、lambda表达式(匿名函数)
  • 五、函数装饰器:增强函数功能

    • 1、基本装饰器示例
    • 2、带参数的装饰器
    • 3、类装饰器
  • 六、函数最佳实践与常见模式

    • 1、文档字符串规范
    • 2、类型注解 (Python 3.5+)
    • 3、函数缓存 (memoization)
    • 4、生成器函数(惰性计算)
  • 七、综合应用案例:Web请求处理器

  • 总结



一、函数基础:定义与调用

1. 基本语法结构

def 函数名(参数列表):
    """函数文档字符串(可选)"""
    函数体
    return 返回值  # 可选

2. 最简单的函数示例

def greet():
    """一个简单的问候函数"""
    print("Hello, Python!")

# 调用函数
greet()  # 输出: Hello, Python!

3. 带参数的函数

def greet_person(name):
    """带参数的问候函数"""
    print(f"Hello, {name}!")

greet_person("Alice")  # 输出: Hello, Alice!

4. 返回值的使用

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

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



二、参数传递机制详解

1、必须参数

调用函数时,Python必须将函数调用中的每个实参都关联到函数定义中的一个形参。为此,最简单的关联方式是基于位置把每个相应位置的实参和形参相关联,调用时的数量必须和声明时的一样。

# 该案例演示了函数位置实参
def func(a, b, c):
    print(a, b, c)
func(1, 2, 3)  # 1 2 3

# 可以看到,1传给了a,2传给了b,3传给了c

2、关键字参数

函数调用使用关键字参数来确定每个变量传入的参数值,使用关键字参数允许函数调用时参数的顺序与声明时不一致。

# 该案例演示了函数调用时的关键字参数
def printInfo(name,age) :
    print("姓名:",name)
    print("年龄:",age)


# Python解释器可以通过age和name这样的关键字去和形参进行匹配
printInfo(name = "zhangsan",age = 18)
printInfo(age = 18,name = "zhangsan")

3、默认值参数

定义函数时,可给每个形参指定默认值。在调用函数时,给形参提供了实参则使用指定的实参值,否则使用形参的默认值。因此,给形参指定默认值后,可在函数调用中省略相应的实参。使用默认值可简化函数调用,还可清楚地指出函数的典型用法。注意:非默认参数必须放在默认参数之前

# 该案例演示了函数调用时的默认参数
def printInfo(name, age = 20) :
    print("姓名:",name)
    print("年龄:",age)

printInfo("zhangsan")

printInfo("lisi",30)

printInfo(age = 40,name = "wangwu")

4、不定长参数

参数的个数是不确定的。

语法
def 函数名([普通参数,] *var_args_tuple ):
   函数体
示例
# 该案例演示了函数调用时的不定长参数
def printInfo(num,*vartuple):
    print(num)
    print(vartuple)

printInfo(70,60,50)
注意
加了星号 * 的参数会以元组(tuple)的形式导入,存放所有未命名的变量参数。

如果形参中出现了不定长参数,那么在调用函数的时候,先通过位置进行必须参数的匹配,然后不定长参数后面的参数必须通过关键字参数匹配

如果不定长的参数后面还有参数,必须通过关键字参数传参

还有一种就是参数带两个星号 **的可变长参数,基本语法如下:

def 函数名([普通参数,] **var_args_dict ):
   函数体

加了两个星号 ** 的参数会以字典的形式导入,后面就不能再有其他参数了

# 该案例演示了函数调用时的不定长参数
def printInfo(num,**vardict):
    print(num)
    print(vardict)
    # return

printInfo(10,key1 = 20,key2 = 30)
printInfo(10,a = 20,b = 30)

5、可变参数 (*args)

<font style="color:rgb(15, 17, 21);background-color:rgb(235, 238, 242);">*args</font> 允许函数接受任意数量的位置参数,这些参数会被打包成一个元组

def calculate_average(*numbers):
    """计算任意数量数字的平均值"""
    if not numbers:
        return 0
    return sum(numbers) / len(numbers)

print(calculate_average(1, 2, 3))           # 输出:2.0
print(calculate_average(10, 20, 30, 40))    # 输出:25.0
def wrapper(*args):
    print(f"接收到位置参数: {args}")
    print(f"类型: {type(args)}")  # tuple
    print(f"长度: {len(args)}")

# 测试不同调用方式
wrapper(1, 2, 3)           # args = (1, 2, 3)

wrapper("a", "b")          # args = ('a', 'b')

wrapper()                  # args = ()

wrapper([1, 2], {3: 4})    # args = ([1, 2], {3: 4})

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

<font style="color:rgb(15, 17, 21);background-color:rgb(235, 238, 242);">**kwargs</font> 允许函数接受任意数量的关键字参数,这些参数会被打包成一个字典

def create_profile(**info):
    """创建用户资料字典"""
    for key, value in info.items():
        print(f"{key}: {value}")

create_profile(name="Charlie", age=28, occupation="Engineer")
# 输出:
# name: Charlie
# age: 28
# occupation: Engineer
def wrapper(**kwargs):
    print(f"接收到关键字参数: {kwargs}")
    print(f"类型: {type(kwargs)}")  # dict

# 测试不同调用方式
wrapper(name="Alice", age=30)     # kwargs = {'name': 'Alice', 'age': 30}
wrapper()                         # kwargs = {}
wrapper(x=1, y=2, z=3)            # kwargs = {'x': 1, 'y': 2, 'z': 3}
def wrapper(*args, **kwargs):
    print(f"位置参数: {args}")
    print(f"关键字参数: {kwargs}")

# 可以接受任何形式的参数
wrapper(1, 2, 3, name="Alice", age=30)
# 输出:
# 位置参数: (1, 2, 3)
# 关键字参数: {'name': 'Alice', 'age': 30}
# *args:接收任意数量的位置参数 → 元组
def sum_all(*args):
    total = 0
    for num in args:
        total += num
    return total

print(sum_all(1, 2, 3))          # 6
print(sum_all(1, 2, 3, 4, 5))    # 15



# **kwargs:接收任意数量的关键字参数 → 字典
def print_info(**kwargs):
    for key, value in kwargs.items():
        print(f"{key}: {value}")

print_info(name="Alice", age=25, city="北京")
# 输出:
# name: Alice
# age: 25
# city: 北京


# 结合使用(顺序:位置参数 > *args > 默认参数 > **kwargs)
def example(a, b, *args, c=10, **kwargs):
    print(f"a={a}, b={b}, args={args}, c={c}, kwargs={kwargs}")


example(1, 2, 3, 4, c=20, x=100, y=200)
# a=1, b=2, args=(3, 4), c=20, kwargs={'x': 100, 'y': 200}

7、参数解包示例

def print_coordinates(x, y, z):
    print(f"坐标: ({x}, {y}, {z})")

coords = (10, 20, 30)
print_coordinates(*coords)  # 等价于 print_coordinates(10, 20, 30)

person = {"name": "David", "age": 35}

def print_person(name, age):
    print(f"{name} is {age} years old")

print_person(**person)  # 等价于 print_person(name="David", age=35)

8、递归

概念

递归一种是逻辑思想,将一个大工作分为逐渐减小的小工作,比如说一个和尚要搬50块石头,他想,只要先搬走49块,那剩下的一块就能搬完了,然后考虑那49块,只要先搬走48块,那剩下的一块就能搬完了……,递归是一种思想,只不过在程序中,就是依靠函数嵌套这个特性来实现了

递归案例求一个整数n的阶乘!:
# 该案例演示了求整数的阶乘
    5! = 5 * 4 * 3 * 2 *1

# 不使用递归的方式
def get_factorial(num):
    res = 1 #  用于存放积
    for n in range(1,num+1):
        res *= n    
    return res
print(get_factorial(5))
print("-"*20)

# 递归
def get_factorial2(n):
    return n * get_factorial2(n - 1) if n > 1 else 1

print(get_factorial2(5))  # 120
递归执行流程分析



三、函数作用域与生命周期

1. 变量作用域规则

x = 10  # 全局变量

def scope_demo():
    y = 20  # 局部变量
    print(f"函数内访问全局变量 x: {x}")
    # print(z)  # 会引发 NameError, z 未定义

scope_demo()
# print(y)  # 会引发 NameError, y 是局部变量

2. global 关键字

count = 0

def increment():
    global count  # 声明使用全局变量
    count += 1

increment()
print(count)  # 输出: 1

3. nonlocal 关键字(嵌套函数中使用)

def outer():
    x = 10
    def inner():
        nonlocal x  # 声明使用外层函数的变量
        x += 5
    inner()
    print(x)  # 输出: 15

outer()



四、高阶函数与函数式编程

1. 函数作为参数传递

def apply_operation(x, y, operation):
    """应用传入的运算函数"""
    return operation(x, y)

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

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

print(apply_operation(3, 4, add))      # 输出: 7
print(apply_operation(3, 4, multiply)) # 输出: 12

2. 函数作为返回值(闭包)

闭包(Closure)是指在一个外部函数中定义的内部函数,该内部函数引用了外部函数的变量,并且外部函数返回了这个内部函数。即使外部函数已经执行完毕,内部函数仍然可以访问外部函数的变量

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
def outer_function(x):
    # 外部函数的局部变量
    y = 10
    
    def inner_function(z):
        # 内部函数引用了外部函数的变量 x 和 y
        return x + y + z
    
    return inner_function

# 创建闭包
closure = outer_function(5) # 5 + 10 + z
print(closure(3))  # 输出: 18 (5 + 10 + 3)



五、函数装饰器:增强函数功能

1. 基本装饰器示例

def my_decorator(func):
    """一个简单的装饰器,打印函数调用信息"""
    def wrapper():
        print("函数调用前...")
        func()
        print("函数调用后...")
    return wrapper

@my_decorator
def say_hello():
    print("Hello!")

等价于
def say_hello():
    print("Hello!")
func = my_decorator(say_hello)

say_hello()

# 输出:
# 函数调用前...
# Hello!
# 函数调用后...

2. 带参数的装饰器

def logger(func):
    def wrapper(*args, **kwargs):
        print(f"调用函数: {func.__name__}")
        print(f"参数: {args}, {kwargs}")
        result = func(*args, **kwargs)
        print(f"返回值: {result}")
        return result
    return wrapper

@logger
def add(x, y):
    return x + y

@logger
def multiply(x, y):
    return x * y

add(3, 5)
multiply(4, 6)

3. 类装饰器

类装饰器是指使用类来实现的装饰器,通过 <font style="color:rgb(15, 17, 21);background-color:rgb(235, 238, 242);">__init__</font><font style="color:rgb(15, 17, 21);background-color:rgb(235, 238, 242);">__call__</font> 方法来实现装饰逻辑。

class TimerDecorator:
    """计算函数执行时间的类装饰器"""
    def __init__(self, func):
        self.func = func

    def __call__(self, *args, **kwargs):
        import time
        start_time = time.time()
        result = self.func(*args, **kwargs)
        end_time = time.time()
        print(f"{self.func.__name__} 执行时间: {end_time - start_time:.4f}秒")
        return result

@TimerDecorator
def slow_function(n):
    """模拟耗时操作"""
    import time
    time.sleep(n)
    return "完成"

slow_function(2)

# 输出:
# slow_function 执行时间: 2.0001秒
# 完成
# 最简单的类装饰器
class SimpleDecorator:
    def __init__(self, func):
        self.func = func
    
    def __call__(self, *args, **kwargs):
        print("函数执行前")
        result = self.func(*args, **kwargs)
        print("函数执行后")
        return result

@SimpleDecorator
def hello():
    print("Hello, World!")

hello()
# 输出:
# 函数执行前
# Hello, World!
# 函数执行后



六、函数最佳实践与常见模式

1. 文档字符串规范

def calculate_discount(price, discount_rate, max_discount=0.5):
    """计算折扣后的价格

    参数:
        price (float): 原始价格
        discount_rate (float): 折扣率 (0-1)
        max_discount (float): 最大允许折扣率 (默认0.5)

    异常:
        ValueError: 如果折扣率超出允许范围
    """
    if discount_rate > max_discount:
        raise ValueError(f"折扣率不能超过{max_discount}")
    return price * (1 - discount_rate)

2. 类型注解(Python 3.5+)

from typing import Callable, Any, Optional

def process_item(
    item: Any,
    transform: Callable[[Any], Any] = lambda x: x,
    logger: Optional[Callable[[str], None]] = None
) -> Any:
    """处理项目并返回结果,可选记录日志"""
    processed = transform(item)
    if logger:
        logger(f"Processed: {processed}")
    return processed

3. 函数缓存(memoization)

from functools import lru_cache

@lru_cache(maxsize=128)
def fibonacci(n):
    """带缓存的斐波那契数列"""
    if n < 2:
        return n
    return fibonacci(n-1) + fibonacci(n-2)

print(fibonacci(30))  # 快速计算,得益于缓存

4. 生成器函数(惰性计算)

def count_up_to(max_num):
    """生成从1到max_num的数字生成器"""
    count = 1
    while count <= max_num:
        yield count
        count += 1

for number in count_up_to(5):
    print(number)  # 输出:1 2 3 4 5



七、匿名函数

1、语法

Python使用 lambda 来定义匿名函数,所谓匿名,指其不用 def 的标准形式定义函数。

lambda 参数列表: 表达式

lambda 是一个表达式,函数体比def简单很多。

lambda的主体是一个表达式,而不是一个代码块,所以仅仅能在lambda表达式中封装有限的逻辑进去。

lambda函数拥有自己的命名空间,且不能访问自己参数列表之外或全局命名空间里的参数。
2、使用普通函数传参

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

def function(a, b, operator):
    return operator(a, b)

print(function(1, 2, ))

3、使用匿名函数传参

def function(a, b, operator):
    return operator(a, b)

print(function(1, 2, lambda x, y: x + y))

4、使用匿名函数传参

可以将匿名函数与常用的内置参数搭配使用。

1、 sorted()

有三名学生的姓名和年龄,按年龄排序。


student_list = [{"name": "zhang3", "age": 36}, {"name": "li4", "age": 14}, {"name": "wang5", "age": 27}]

print(sorted(student_list, key=lambda x: x["age"]))

2、 map(),map() 函数对序列中元素逐一处理


map_result = map(lambda x: x * x, [0, 1, 3, 7, 9])

print(list(map_result))  # [0, 1, 9, 49, 81]

3、 filter(),filter() 函数对序列中元素过滤


filter_result = filter(lambda x: x >= 0, [-0, -1, -3, 7, 9])

print(list(filter_result))  # [0, 7, 9]

4、 reduce(),reduce() 函数对序列中元素进行累积


from functools import reduce

reduce_result = reduce(lambda x, y: x * y, [1, 2, 3, 4, 5])

print(reduce_result)  # 120



八、综合应用案例:Web请求处理器

from functools import wraps
import time

def handle_errors(func):
    """错误处理装饰器"""
    @wraps(func)
    def wrapper(*args, **kwargs):
        try:
            return func(*args, **kwargs)
        except Exception as e:
            print(f"请求处理错误: {str(e)}")
            return {"error": "Internal server error"}, 500
    return wrapper

def validate_input(required_fields):
    """输入验证装饰器工厂"""
    def decorator(func):
        @wraps(func)
        def wrapper(data, *args, **kwargs):
            missing = [field for field in required_fields if field not in data]
            if missing:
                return {"error": f"Missing fields: {', '.join(missing)}"}, 400
            return func(data, *args, **kwargs)
        return wrapper
    return decorator

@handle_errors
@validate_input(["name", "email"])
def process_user_request(data):
    """处理用户请求"""
    # 模拟耗时操作
    time.sleep(0.1)

    # 处理逻辑...
    return {
        "message": "User created successfully",
        "user": {
            "name": data["name"],
            "email": data["email"]
        }
    }

# 测试请求处理
test_data = {"name": "Alice", "email": "alice@example.com"}
response = process_user_request(test_data)
print(f"响应内容: {response}")



总结

  • 1、函数基础:掌握 def 定义、参数传递、返回值等基本概念
  • 2、参数处理:理解位置参数、关键字参数、默认参数、可变参数(*args, **kwargs)
  • 3、作用域规则:区分全局变量、局部变量,合理使用 globalnonlocal
  • 4、高阶特性
    • 函数作为一等公民(参数、返回值)
    • 闭包与 lambda 表达式
    • 装饰器模式(函数增强)
  • 5、实用技巧
    • 文档字符串规范
    • 类型注解
    • 缓存与生成器
    • 错误处理装饰器
posted @ 2026-08-05 21:00  jock_javaEE  阅读(4)  评论(0)    收藏  举报