# 函数 # 语法 # def function_name(parameters): # """文档字符串(可选)""" # # 函数体 # return value # 可选 # 组成部分: # 函数名:标识函数的名称,遵循变量命名规则 # 参数列表:括号中的变量名,表示调用时可以传递的值 # 函数体:缩进的代码块,包含具体的实现逻辑 # 返回值:通过return语句将结果返回给调用者 # 定义 # Python要求函数体代码必须缩进(通常为4个空格) def square(x): return x**2 print(square(2)) # 可以在函数内部定义文档字符串(docstring),用于描述函数的作用: def square(x): """ 求x的平方 """ return x**2 # 参数类型 # 1.位置参数:位置参数是最基本的参数类型,调用函数时按照参数的位置一一对应传递。 # 特点: # 参数的顺序很重要,不能颠倒 # 调用时必须提供所有必需参数 # 参数按位置顺序赋值 def add(a, b): return a + b result = add(1, 2) print(result) # 2.关键字参数:关键字参数允许你在调用函数时,通过"参数名=值"的形式传递参数,这样参数顺序就可以任意。 # 优点: # 不用记住参数顺序 # 增加代码可读性 # 很适合带有默认参数的函数 def student_info(name, age, city): return f"姓名{name},年龄{age},城市{city}" print(student_info(age=18, name="小明", city="beijing")) # 3.默认参数:默认参数是指在定义函数时为参数提供默认值。在调用函数时,如果对应参数没有传值,则会使用这个默认值。 # 注意事项: # 默认参数必须出现在非默认参数之后 # 默认参数常用于大多数情况下使用同一个值的场景 def greet(name, msg="Hello"): print(f"{msg}, {name}!") greet("Alice") # 输出:Hello, Alice! greet("Bob", msg="Hi") # 输出:Hi, Bob! # 4.可变参数:可变参数用于当函数需要接受不定数量的位置参数时,通过在参数前加*来实现。 # 特点: # *args不是必须叫args,但习惯上都叫args # 所有传入的位置参数被收集到一个元组中 # 特别适合参数数量不确定时使用 def show_args(*args): print(f"参数类型{type(args)}") print(f"参数内容{args}") show_args(1, 2, 4) # 参数类型 参数内容(1, 2, 4) show_args([1, 2, 3]) # 参数类型 参数内容([1, 2, 3],) show_args("123") # 参数类型 参数内容('123',) # 应用 def make_pizza(*foods): print("制作一个披萨,添加以下配料:") for food in foods: print(f"-{food}") make_pizza("蘑菇", "青椒", "芝士") # 5.关键字可变参数:关键字可变参数允许函数接收任意数量的"关键字参数"。这些参数会被自动收集到一个字典中。 # **kwargs不是必须叫kwargs,习惯上都这么命名 # 多余的关键字参数汇集到一个字典里 # 常用于不确定会传入哪些命名参数时 def show_kwargs(**kwargs): print(f"参数类型{type(kwargs)}") print(f"参数内容{kwargs}") show_kwargs(name="1", age=18) # 参数类型 参数内容{'name': '1', 'age': 18} # 综合 def demo(a, *args, b=1, **kwargs): print(f"a:{a}") # a:小明 print(f"args:{args}") # args:(20, 30) print(f"b:{b}") # b:北京 print(f"kwargs:{kwargs}") # kwargs:{'x': '8', 'y': 10} demo("小明", 20, 30, b="北京", x="8", y=10) # 参数解包 # 在Python中,*和**不仅可以用于函数定义时接收可变参数,还可以用于参数解包。 def greet(name, age, city): print(f"姓名: {name}, 年龄: {age}, 城市: {city}") # 使用 * 解包列表 person_info = ["Alice", 25, "北京"] greet(*person_info) # 等同于 greet("Alice", 25, "北京") # 使用 * 解包元组 data = ("Bob", 30, "上海") greet(*data) # 等同于 greet("Bob", 30, "上海") # ** 用于解包字典类型 def create_profile(name, age, city, occupation): print(f"姓名: {name}, 年龄: {age}, 城市: {city}, 职业: {occupation}") # 使用 ** 解包字典 profile_data = {"name": "Charlie", "age": 28, "city": "广州", "occupation": "工程师"} create_profile(**profile_data) # 混合使用 def complex_function(a, b, c, d, e): print(f"a: {a}, b: {b}, c: {c}, d: {d},e:{e}") list_data = [1, 2] dict_data = {"d": 10, "e": "小明"} complex_function(*list_data, True, **dict_data) # 返回值 # 返回单个值 def get_formatted_name(first_name, last_name): full_name = f"{first_name}{last_name}" return full_name musician = get_formatted_name("张", "三") print(musician) # 张三 # 返回多个值 def operate_numbers(a, b): sum_result = a + b diff_result = a - b product_result = a * b return sum_result, diff_result, product_result # 接收元组 result = operate_numbers(10, 5) print(result) # (15, 5, 50) # 解包返回值 sum_val, diff_val, product_val = operate_numbers(10, 5) print(f"Sum: {sum_val}, Difference: {diff_val}, Product: {product_val}") def create_student_report(name, **scores): report = {"name": name, "total_score": 0, "subjects": scores} for key, score in scores.items(): print(f"{key}:{score}") # # 计算总分 for score in scores.values(): report["total_score"] += score # # 计算平均分 report["average"] = report["total_score"] / len(scores) return report student = create_student_report("Alice", **{"math": 95, "science": 87, "english": 92}) print(student) # 函数文档和注释 # 文档字符串(Docstring) # 文档字符串是紧跟在函数定义后,用三引号包裹的字符串,用于描述函数的用途、参数说明、返回值类型等。 def calculate_circle_area(radius): """ 计算圆的面积 参数: radius (float): 圆的半径 返回: float: 圆的面积 """ import math return math.pi * radius**2 # 查看文档字符串 print(calculate_circle_area.__doc__) # 查看函数帮助 help(calculate_circle_area) # 注释 # 注释是用#开头的说明性文字,用于解释代码片段的实现思路、注意事项或特殊用途 def safe_divide(a, b): """安全的除法函数""" # 检查除数是否为零 if b == 0: return "错误:除数不能为零" # 执行除法运算 result = a / b return result # 变量作用域 # 作用域类型 # 作用域类型 描述 示例 # 局部作用域 变量在函数内部定义,只能在该函数内部使用 函数内的局部变量 # 全局作用域 变量在所有函数体外部定义,可以在整个模块里访问 模块级别的变量 # 嵌套作用域 内部函数可以访问外部函数中的变量 闭包中的外部变量 # 内置作用域 Python预先定义的内置标识符 len, range, print等 # LEGB原则 # Python采用LEGB原则查找变量: # L: Local(本地作用域) # E: Enclosing(嵌套函数的外部函数作用域) # G: Global(全局作用域) # B: Built-in(内置作用域) name = "全局变量" def outer(): name = "外部函数变量" def inner(): name = "内部函数变量" print(f"inner:{name}") # 输出"内部函数变量" inner() print(f"outer:{name}") # 输出"外部函数变量" outer() print(name) # 输出"全局变量" # global关键字 # global关键字允许我们在函数内部声明某个变量为全局变量,从而可以在函数内部修改它。 # 注意事项: # 没有global关键字时,在函数内对一个变量赋值会将其作为局部变量处理 # 使用global后,函数内的变量就直接引用外部全局变量 counter = 0 def increment(): global counter # 引用外部全局变量 counter += 1 increment() increment() print(counter) # 2 # nonlocal关键字 # nonlocal关键字用于在嵌套函数中声明变量来自最近的一层非全局作用域(外层函数)。 def outer(): x = "local" def inner(): nonlocal x # 声明 x 来自外层作用域 x = "nonlocal" print(f"inner:{x}") # inner:nonlocal inner() print(f"outer:{x}") # outer:nonlocal outer() # 高级函数特性 # 8.1.函数作为参数 # 函数不仅可以像变量一样赋值给其他变量,还可以作为参数传递给其他函数。 def apply_operation(numbers, operation): """对数字列表应用操作""" return [operation(x) for x in numbers] def square(x): return x**2 def double(x): return x * 2 numbers = [1, 2, 3, 4, 5] squared = apply_operation(numbers, square) doubled = apply_operation(numbers, double) print(squared) # [1, 4, 9, 16, 25] print(doubled) # [2, 4, 6, 8, 10] # 嵌套函数 # 嵌套函数是指在一个函数内部定义另一个函数。内部函数可以访问外部函数的参数和局部变量。 # 用途: # 实现闭包(closure) # 将某些逻辑封装到本地作用域 # 作为工厂函数创建带记忆的数据 def greet(name): def format_message(): return f"Hello, {name}!" return format_message() print(greet("Alice")) # Hello, Alice! # 闭包 # 闭包是指一个函数可以"记住"它被创建时的环境,即使在其外部函数已经执行完毕后,内部函数依然能够访问其外部作用域的变量。 # 特点: # 内部函数引用了外部函数的局部变量 # 外部函数返回内部函数 # 内部函数可以访问外部函数的变量,即使外部函数已经执行完毕 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 my_decorator(func): def wrapper(): print("函数执行前") func() print("函数执行后") return wrapper @my_decorator def say_hello(): print("Hello") say_hello() # 函数执行前 Hello 函数执行后 # 带参数的装饰器 def logger(func): def wrapper(*args, **kwargas): print(f"调用函数{func.__name__},参数:{args}{kwargas}") return func(*args, **kwargas) return wrapper @logger def add(x, y, **kwargs): a = x + y b = sum(kwargs.values()) return a + b print(add(1, 2, a=3, b=4)) # 匿名函数 (Lambda) # 匿名函数(lambda表达式)是一种快速定义简单函数的方法,通常用于一些无需命名、只用一次的小函数场景。 # lambda 参数1, 参数2, ... : 表达式 # 基本 lambda 函数 # 特点: # 只能包含表达式,不能包含语句 # 自动返回表达式的值 # 适合简单的函数逻辑 square = lambda x: x**2 print(square(5)) # 25 # 在排序中使用 students = [ {"name": "Alice", "grade": 85}, {"name": "Bob", "grade": 92}, {"name": "Charlie", "grade": 78}, ] # 按成绩排序 sorted_students = sorted(students, key=lambda x: x["grade"]) print(sorted_students) # 在 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] # 递归函数 # 递归函数是函数调用自身来解决问题的方法,适合解决可以被分解为规模更小、相似子问题的任务。 # def func(params): # if 终止条件: # return 结果 # else: # # 递归调用自身 # return func(更小规模的参数) # 注意事项: # 必须设置基线条件(终止条件),避免无限递归 # 递归深度有限制,可能导致栈溢出 # 对于规模较大的问题效率较低 def factorial(n): """计算阶乘的递归函数""" if n == 0 or n == 1: return 1 else: return n * factorial(n - 1) print(factorial(5)) # 120 def fibonacci(n): """计算斐波那契数列""" if n <= 1: return n else: return fibonacci(n - 1) + fibonacci(n - 2) for i in range(10): print(fibonacci(i), end=" ") # 0 1 1 2 3 5 8 13 21 34 # 错误处理 # 在函数中进行错误处理可以提升程序的健壮性和用户体验。 # def 函数名(参数): # try: # # 可能抛出异常的操作 # except 异常类型1: # # 异常类型1的处理代码 # except 异常类型2: # # 异常类型2的处理代码 # else: # # 没有发生异常时的代码 # finally: # # 无论是否发生异常都执行 def safe_divide(a, b): """安全的除法函数""" try: result = a / b except ZeroDivisionError: return "错误:除数不能为零" except TypeError: return "错误:参数类型不正确" else: return result print(safe_divide(10, 2)) # 5.0 print(safe_divide(10, 0)) # 错误:除数不能为零 print(safe_divide(10, "a")) # 错误:参数类型不正确 # 最佳实践 # 14.1.函数设计原则 # 单一职责:每个函数只做一件事 # 描述性命名:使用有意义的函数名 # 保持简短:函数应该简短且专注 # 使用文档字符串:为函数添加适当的文档 # 避免副作用:函数不应该修改外部状态,除非明确需要 # 14.2.参数设计 # 合理使用默认参数:使函数更灵活 # 参数顺序:位置参数在前,默认参数在后 # 使用*args和kwargs**:提高函数灵活性 # 参数验证:在函数开始处验证参数 # 14.3.错误处理 # 处理异常:在适当的地方处理可能的错误 # 提供有意义的错误信息:帮助用户理解问题 # 使用try-except:优雅地处理异常情况 # 14.4.性能考虑 # 避免不必要的计算:将重复计算提取到函数外部 # 使用生成器:对于大数据集使用生成器函数 # 缓存结果:对于昂贵的计算考虑缓存 # 15.总结 # 函数是Python编程的核心概念,掌握函数的定义、调用、参数传递、返回值、作用域等概念对于编写高质量的Python代码至关重要。通过合理使用函数,我们可以: # 提高代码的可重用性和可维护性 # 实现模块化编程 # 简化复杂问题的解决 # 提高代码的可读性和可测试性 # 掌握函数的高级特性如闭包、装饰器、递归等,能够让我们编写更加灵活和强大的Python程序。