Python入门之函数

1. 函数介绍

函数是Python中组织代码的核心结构,用于封装可重用的逻辑。除了内置函数(如print()、len()),我们还可以通过def语句自定义函数,实现代码模块化与复用。以下是关于函数的详细说明,包含核心概念、示例及扩展知识。

2. 函数的定义与调用

函数通过def语句定义,基本语法为:

def 函数名(参数列表):
    函数体(缩进代码块)
    [return 返回值]

核心特点:

  • 函数体必须缩进(通常 4 个空格),以区分函数内外代码。
  • 函数必须先定义后调用,否则会触发NameError。
  • 函数体仅在调用时执行。

示例:定义一个无参数函数,打印指定内容

# 定义函数
def greet():
    """打印问候语三次"""
    for _ in range(3):
        print("你好,Loen")

# 调用函数(必须在定义之后)
greet()
# 输出:
# 你好,Loen
# 你好,Loen
# 你好,Loen

3. 函数参数

参数是函数与外部交互的接口,用于向函数传递数据。根据使用方式,参数可分为多种类型。

3.1 形参与实参

  • 形参(形式参数):函数定义时括号内的变量(如name),仅在函数内部有效。
  • 实参(实际参数):函数调用时传递给形参的具体值(如”Alice”)。

示例:形参与实参

def say_hello(name):  # name 是形参
    print(f"你好,{name}!")

say_hello("Alice")  # "Alice" 是实参
# 输出:你好,Alice!

3.2 多参数与参数顺序
多个参数用逗号分隔,调用时实参顺序需与形参一致(位置参数)。
示例:多参数函数

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

introduce("Bob", 18)  # 按顺序传递实参
# 输出:我叫Bob,今年18岁。

3.3 关键字参数
调用函数时,可通过形参名=值的形式指定参数,无需严格遵循顺序,增强代码可读性。
示例:关键字参数

introduce(age=20, name="Charlie")  # 用关键字指定参数
# 输出:我叫Charlie,今年20岁。

3.4 默认参数
定义函数时,可为形参设置默认值(形参=默认值)。调用时若不传递该参数,则使用默认值。注意:默认参数必须放在非默认参数之后。
示例:默认参数

def order_drink(drink, sugar="正常糖"):  # sugar 是默认参数
    print(f"点一杯{drink},{sugar}。")

order_drink("奶茶")  # 不传递sugar,使用默认值
# 输出:点一杯奶茶,正常糖。

order_drink("咖啡", "少糖")  # 传递sugar,覆盖默认值
# 输出:点一杯咖啡,少糖。

坑点:默认参数不应设为可变对象(如列表、字典),否则可能导致意外结果:

# 错误示例:默认参数为可变对象
def add_item(item, items=[]):
    items.append(item)
    return items

print(add_item("苹果"))  # 输出:['苹果']
print(add_item("香蕉"))  # 输出:['苹果', '香蕉'](意外保留了之前的结果)

正确做法:默认值设为None,在函数内初始化可变对象:

def add_item(item, items=None):
    if items is None:
        items = []
    items.append(item)
    return items

print(add_item("苹果"))  # 输出:['苹果']
print(add_item("香蕉"))  # 输出:['香蕉'](符合预期)

4. 可变参数(收集参数)

当参数数量不确定时,可使用args和*kwargs收集参数:

  • *args:收集所有位置参数,打包为元组(tuple)。
  • **kwargs:收集所有关键字参数,打包为字典(dict)。

示例1:args收集位置参数

def sum_numbers(*args):
    print("收集的参数:", args)  # args 是元组
    return sum(args)

print(sum_numbers(1, 2, 3))  # 传递3个位置参数
# 输出:
# 收集的参数: (1, 2, 3)
# 6

print(sum_numbers(10, 20))  # 传递2个位置参数
# 输出:
# 收集的参数: (10, 20)
# 30

示例2:kwargs收集关键字参数

def print_info(**kwargs):
    print("收集的参数:", kwargs)  # kwargs 是字典
    for key, value in kwargs.items():
        print(f"{key}: {value}")

print_info(name="Diana", age=22, city="Beijing")
# 输出:
# 收集的参数: {'name': 'Diana', 'age': 22, 'city': 'Beijing'}
# name: Diana
# age: 22
# city: Beijing

组合使用:args必须在**kwargs之前,且普通参数需放在最前:

def func(a, b, *args, **kwargs):
    print(f"普通参数:a={a}, b={b}")
    print(f"位置参数集合:{args}")
    print(f"关键字参数集合:{kwargs}")

func(1, 2, 3, 4, x=5, y=6)
# 输出:
# 普通参数:a=1, b=2
# 位置参数集合:(3, 4)
# 关键字参数集合:{'x': 5, 'y': 6}

5. 参数解包

与args/kwargs相反,可通过和将序列或字典解包为参数:

  • *序列:将序列(列表、元组等)解包为位置参数。
  • **字典:将字典解包为关键字参数。

示例:参数解包

def func(a, b, c):
    print(a + b + c)

# 解包列表为位置参数
nums = [1, 2, 3]
func(*nums)  # 等价于 func(1, 2, 3)
# 输出:6

# 解包字典为关键字参数
info = {"a": 10, "b": 20, "c": 30}
func(** info)  # 等价于 func(a=10, b=20, c=30)
# 输出:60

6. 参数传递的本质

Python中参数传递是 “传对象引用”:

  • 若传递不可变对象(如整数、字符串、元组),函数内修改不会影响外部。
  • 若传递可变对象(如列表、字典),函数内修改会影响外部。

示例:参数传递与对象可变性

# 不可变对象(整数)
def modify_int(x):
    x = 100  # 重新赋值,不影响外部
    print("函数内x:", x)

num = 10
modify_int(num)
print("函数外num:", num)
# 输出:
# 函数内x: 100
# 函数外num: 10

# 可变对象(列表)
def modify_list(lst):
    lst.append(4)  # 修改原列表,影响外部
    print("函数内列表:", lst)

my_list = [1, 2, 3]
modify_list(my_list)
print("函数外列表:", my_list)
# 输出:
# 函数内列表: [1, 2, 3, 4]
# 函数外列表: [1, 2, 3, 4]

7. 函数返回值

函数通过return语句返回结果,调用者可接收并使用该结果。

核心特点:

  • return后可跟任意类型的值(或表达式)。
  • 函数若未显式写return,默认返回None。
  • return会立即终止函数执行,后续代码不再运行。
  • 可返回多个值(本质是返回元组,调用时可解包)。

示例1:基本返回值

def add(a, b):
    return a + b  # 返回计算结果

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

示例2:return终止函数

def check_positive(n):
    if n > 0:
        return "正数"
    print("这句不会执行(若n>0)")  # return 后代码不执行

print(check_positive(5))  # 输出:正数

示例3:返回多个值

def get_user():
    name = "Eve"
    age = 25
    return name, age  # 等价于 return (name, age)

user_name, user_age = get_user()  # 解包返回值
print(user_name, user_age)  # 输出:Eve 25

8. 函数的注释与文档字符串

注释用于解释代码逻辑,文档字符串(docstring)用于描述函数功能,可通过help()函数查看。

  • 单行注释:用#开头,仅注释单行。
  • 文档字符串:用”””或”””包裹,可跨多行,通常放在函数定义的第一行。

示例:注释与文档字符串

def calculate_area(radius):
    """
    计算圆的面积。
    
    参数:
        radius (float): 圆的半径(必须为正数)。
    
    返回:
        float: 圆的面积(π * radius²)。
    
    异常:
        ValueError: 若半径为负数或零,抛出异常。
    """
    if radius <= 0:
        raise ValueError("半径必须为正数")
    import math
    return math.pi * radius ** 2  # 计算面积

# 查看文档字符串
help(calculate_area)
# 输出:
# Help on function calculate_area in module __main__:
# calculate_area(radius)
#    计算圆的面积。
#    
#    参数:
#        radius (float): 圆的半径(必须为正数)。
#    
#    返回:
#        float: 圆的面积(π * radius²)。
#    
#    异常:
#        ValueError: 若半径为负数或零,抛出异常。

9. 函数对象特性

在Python中,函数是 “一等公民”,可像其他数据类型一样被操作:

  • 赋值给变量。
  • 作为参数传递给其他函数。
  • 作为返回值从函数中返回。

示例1:函数赋值给变量

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

func_var = multiply  # 函数赋值给变量
print(func_var(3, 4))  # 通过变量调用函数,输出:12

示例2:函数作为参数传递

def apply_func(func, x, y):
    """将函数func应用于x和y"""
    return func(x, y)

# 传递内置函数max
print(apply_func(max, 5, 10))  # 输出:10

# 传递自定义函数multiply
print(apply_func(multiply, 5, 10))  # 输出:50

示例3:函数作为返回值

def make_adder(n):
    """返回一个“累加n”的函数"""
    def adder(x):
        return x + n
    return adder  # 返回内部定义的函数

add_5 = make_adder(5)  # 获取“加5”的函数
print(add_5(3))  # 输出:8(3+5)

add_10 = make_adder(10)
print(add_10(3))  # 输出:13(3+10)

10. 变量作用域

变量的作用域指其可被访问的范围,分为:

  • 局部变量:函数内部定义的变量,仅在函数内有效。
  • 全局变量:函数外部定义的变量,可在整个模块中访问。
  • 嵌套作用域:嵌套函数中,外层函数的变量对内存函数可见(非全局)。

10.1 局部变量与全局变量

# 全局变量
global_var = "我是全局变量"

def my_func():
    # 局部变量(仅在函数内有效)
    local_var = "我是局部变量"
    print(local_var)
    print(global_var)  # 可访问全局变量

my_func()
# 输出:
# 我是局部变量
# 我是全局变量

print(global_var)  # 可访问全局变量
# print(local_var)  # 报错:NameError(局部变量在外部不可见)

10.2 修改全局变量:global关键字

函数内默认不能修改全局变量(会被视为定义局部变量),需用global声明。

示例:修改全局变量

count = 0  # 全局变量

def increment():
    global count  # 声明count是全局变量
    count += 1  # 修改全局变量

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

10.2 修改嵌套作用域变量:nonlocal关键字

在嵌套函数中,若需修改外层函数的变量(非全局),需用nonlocal声明。

示例:嵌套函数与nonlocal

def outer():
    x = 10  # 外层函数的变量(嵌套作用域)
    
    def inner():
        nonlocal x  # 声明x是外层函数的变量
        x += 5  # 修改外层变量
        print("inner中的x:", x)
    
    inner()
    print("outer中的x:", x)  # 外层变量已被修改

outer()
# 输出:
# inner中的x: 15
# outer中的x: 15

11. 变量作用域嵌套函数

函数内部可定义另一个函数(嵌套函数),内部函数可访问外层函数的变量(闭包特性)。

示例:嵌套函数

def outer_func(message):
    def inner_func():
        # 内部函数可访问外层函数的参数
        print(f"内部函数:{message}")
    
    inner_func()  # 外层函数调用内部函数

outer_func("Hello, 嵌套函数!")
# 输出:内部函数:Hello, 嵌套函数!

12. 总结

函数是Python代码组织的核心,掌握函数的定义、参数、返回值、作用域等特性,能大幅提升代码的可读性、复用性和可维护性。灵活运用函数对象特性(如作为参数、返回值),还能实现高阶编程模式(如装饰器、闭包),为复杂逻辑提供简洁解决方案。

原创内容声明

作者 山海
来源平台 山海运维

本文为原创内容,版权归作者所有,未经授权禁止任何形式转载

(0)

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注