# Python 函数完全指南:参数、返回值与高级用法

函数是代码复用的基础。学了函数才知道,Python 写得漂亮的人是怎么把代码组织得那么优雅的。这篇文章把我踩过的坑和实战经验全部分享出来。

函数是什么

简单说,函数就是把一段可以重复使用的代码打包起来,给它起个名字,以后想用就直接调用。

# 定义函数
def greet():
    print("你好!")

# 调用函数
greet()  # 输出: 你好!

函数参数详解

位置参数

按顺序传递,顺序很重要:

def introduce(name, age, city):
    print(f"我叫{name},今年{age}岁,来自{city}")

introduce("张三", 25, "北京")
# 我叫张三,今年25岁,来自北京

# 顺序错了,结果就错了
introduce("北京", 25, "张三")  # 不对!

关键字参数

指定参数名传递,顺序无所谓:

introduce(age=25, city="北京", name="张三")
# 我叫张三,今年25岁,来自北京

默认参数

给参数设置默认值:

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

greet("张三")              # 你好,张三!
greet("李四", "早上好")    # 早上好,李四!

# 默认参数要放最后
# def wrong(a=1, b):  # 错误!
# def correct(a, b=2):  # 正确!

可变参数 *args

不知道会传几个参数时用 *args

def sum_all(*numbers):
    total = 0
    for n in numbers:
        total += n
    return total

print(sum_all(1, 2, 3))        # 6
print(sum_all(10, 20))          # 30
print(sum_all())                # 0

# args 是元组
def print_args(*args):
    print(type(args))  # <class 'tuple'>
    for arg in args:
        print(arg)

关键字参数 **kwargs

传递任意数量的关键字参数:

def print_info(**info):
    print(type(info))  # <class 'dict'>
    for key, value in info.items():
        print(f"{key}: {value}")

print_info(name="张三", age=25, city="北京")
# name: 张三
# age: 25
# city: 北京

# 结合使用
def func(*args, **kwargs):
    print("位置参数:", args)
    print("关键字参数:", kwargs)

func(1, 2, 3, name="张三", age=25)
# 位置参数: (1, 2, 3)
# 关键字参数: {'name': '张三', 'age': 25}

返回值

基本返回

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

result = add(3, 5)
print(result)  # 8

# 没有 return 返回 None
def no_return():
    print("只打印不返回")

print(no_return())  # None

多返回值

Python 函数可以返回多个值(实际是元组):

def divide(a, b):
    quotient = a // b
    remainder = a % b
    return quotient, remainder

q, r = divide(10, 3)
print(f"商: {q}, 余数: {r}")  # 商: 3, 余数: 1

# 也可以接收为元组
result = divide(10, 3)
print(result)  # (3, 1)

Lambda 表达式

lambda 是匿名函数,适合简单函数:

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

# lambda 版本
square = lambda x: x ** 2
print(square(5))  # 25

# 结合内置函数使用
numbers = [5, 2, 8, 1, 9]

# sorted 配合 lambda 按绝对值排序
sorted_nums = sorted(numbers, key=lambda x: -x)  # 降序
print(sorted_nums)  # [9, 8, 5, 2, 1]

# map 配合 lambda
doubled = list(map(lambda x: x * 2, numbers))
print(doubled)  # [10, 4, 16, 2, 18]

# filter 配合 lambda
evens = list(filter(lambda x: x % 2 == 0, numbers))
print(evens)  # [2, 8]

装饰器

装饰器可以在不修改原函数的情况下,给函数添加新功能:

入门装饰器

# 定义装饰器
def my_decorator(func):
    def wrapper():
        print("调用函数之前")
        func()
        print("调用函数之后")
    return wrapper

# 使用装饰器
@my_decorator
def say_hello():
    print("你好!")

say_hello()
# 调用函数之前
# 你好!
# 调用函数之后

# 相当于:
# say_hello = my_decorator(say_hello)

带参数的装饰器

def repeat(times):
    def decorator(func):
        def wrapper(*args, **kwargs):
            for _ in range(times):
                func(*args, **kwargs)
        return wrapper
    return decorator

@repeat(times=3)
def greet(name):
    print(f"你好,{name}!")

greet("张三")
# 你好,张三!
# 你好,张三!
# 你好,张三!

functools.wraps

保留原函数的信息:

import functools

def my_decorator(func):
    @functools.wraps(func)  # 保留原函数信息
    def wrapper(*args, **kwargs):
        print("开始")
        return func(*args, **kwargs)
    return wrapper

@my_decorator
def add(a, b):
    """返回两数之和"""
    return a + b

print(add.__name__)  # add(而不是 wrapper)
print(add.__doc__)   # 返回两数之和(保留了原函数的文档)

实战案例

案例1:计时器

import time
import functools

def timer(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        end = time.time()
        print(f"{func.__name__} 执行耗时: {end - start:.2f}秒")
        return result
    return wrapper

@timer
def slow_function():
    time.sleep(1)
    print("执行完成")

slow_function()
# 执行完成
# slow_function 执行耗时: 1.00秒

案例2:参数验证

def validate(**rules):
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            for param, condition in rules.items():
                if param in kwargs:
                    value = kwargs[param]
                    if 'min' in condition and value < condition['min']:
                        raise ValueError(f"{param} 不能小于 {condition['min']}")
                    if 'max' in condition and value > condition['max']:
                        raise ValueError(f"{param} 不能大于 {condition['max']}")
                    if 'type' in condition and not isinstance(value, condition['type']):
                        raise TypeError(f"{param} 必须是 {condition['type']}")
            return func(*args, **kwargs)
        return wrapper
    return decorator

@validate(age={'min': 0, 'max': 150, 'type': int}, name={'type': str})
def register(name, age):
    print(f"注册成功: {name}, {age}岁")

register(name="张三", age=25)  # 正常
register(name="李四", age=-5)   # ValueError: age 不能小于 0

案例3:缓存装饰器

def cache(func):
    cache_dict = {}
    @functools.wraps(func)
    def wrapper(*args):
        if args in cache_dict:
            print(f"命中缓存: {args}")
            return cache_dict[args]
        result = func(*args)
        cache_dict[args] = result
        return result
    return wrapper

@cache
def fibonacci(n):
    if n < 2:
        return n
    return fibonacci(n - 1) + fibonacci(n - 2)

print(fibonacci(10))  # 55(计算)
print(fibonacci(10))  # 命中缓存:55(直接从缓存取)

我踩过的坑

坑1:默认参数用可变对象

# 错误!默认参数是可变对象会被共享
def add_item(item, items=[]):
    items.append(item)
    return items

print(add_item(1))  # [1]
print(add_item(2))   # [1, 2](不是 [2]!)
print(add_item(3))   # [1, 2, 3]

# 正确做法
def add_item_correct(item, items=None):
    if items is None:
        items = []
    items.append(item)
    return items

print(add_item_correct(1))  # [1]
print(add_item_correct(2))  # [2]
print(add_item_correct(3))  # [3]

坑2:lambda 中的变量作用域

# lambda 中的变量是延迟绑定的
funcs = [lambda x: x + i for i in range(3)]
print([f(0) for f in funcs])  # [3, 3, 3](不是你期望的 [0, 1, 2]!)

# 正确做法:立即绑定参数
funcs = [lambda x, i=i: x + i for i in range(3)]
print([f(0) for f in funcs])  # [0, 1, 2]

坑3:装饰器顺序

@decorator1
@decorator2
def func():
    pass

# 相当于:func = decorator1(decorator2(func))
# 所以执行顺序是:func -> decorator2 -> decorator1

写在最后

函数是 Python 编程的灵魂。掌握好参数传递、返回值、lambda 和装饰器,你的代码会变得简洁又优雅。

我的经验是:好的函数应该做一件事,而且做好这件事。

有帮助的话点个赞,有问题评论区见!

Logo

这里是“一人公司”的成长家园。我们提供从产品曝光、技术变现到法律财税的全栈内容,并连接云服务、办公空间等稀缺资源,助你专注创造,无忧运营。

更多推荐