目录
一,递归函数
递归函数是一种在函数内部调用自身的编程技巧。递归函数通常用于解决可以被分解为相同问题的子问题的情况,每次递归函数调用都会将问题规模缩小,直到达到基本情况(递归终止条件)。
递归函数的基本结构如下:
- 定义递归函数:函数内部包含对自身的调用。
- 设置递归终止条件:当满足某个条件时,停止调用递归函数,并返回结果。
- 分解问题:将原问题分解为更小的子问题,并通过递归函数解决。
- 组合结果:将子问题的解合并为原问题的解
例如,下面是一个计算阶乘的递归函数的示例:
def get_multi(v): if v == 1: return 1 # 递归出口 else: return v * get_multi(v - 1) get_multi(5)
在这个例子中,递归函数get_multi
计算了一个数的阶乘。它的终止条件是v等于1时,返回结果1。否则,它会调用自身,传入v-1
作为参数,并将结果与v相乘返回。
需要注意的是,递归函数需要正确地设置终止条件,否则会导致无限递归,最终引发栈溢出错误。另外,递归函数的效率可能较低,因为它们通常会涉及多次函数调用和重复计算。可以使用递归函数解决问题,但在一些情况下,迭代和循环可能更为高效。
二,匿名函数
1.匿名函数的定义
匿名函数,也称为 lambda 函数,是一种在许多编程语言中支持的特殊类型的函数。它们通常用于需要一个简单函数作为参数的情况,或者在需要一个函数,但又不希望为其定义一个完整的命名函数时使用。
在Python中,lambda 函数的基本语法是:
lambda arguments: expression
其中:
lambda
是关键字,表示这是一个 lambda 函数。arguments
是函数的参数,可以是任意数量的参数,但只能有一个表达式。expression
是返回值表达式,表示 lambda 函数要执行的操作。
例如,定义一个简单的 lambda 函数来计算两个数的和:
add = lambda x, y: x + y print(add(3, 5)) # 输出 8
2.匿名函数的特点和用法
lambda 函数的特点和用法包括:
- 匿名性:lambda 函数是匿名的,即它们不需要通过
def
关键字命名。 - 简洁性:lambda 函数通常用于简单的操作,以提高代码的可读性和简洁性。
- 一次性使用:lambda 函数通常用于一些函数式编程的场景,例如传递给高阶函数(如
map
、filter
、reduce
等)作为参数。
然而,需要注意的是:
- lambda 函数虽然方便,但不适合复杂逻辑的函数。
- lambda 函数的使用应谨慎,因为它们可能会降低代码的可读性,特别是对于非常复杂的表达式或算法。
总结来说,lambda 函数是一种轻量级的、简洁的函数定义方式,适合于一些简单的、非重复使用的函数需求。
三,闭包以及闭包的使用
1.何为闭包
闭包是一种特殊的函数,它可以捕获其外层函数中的变量,并将其保存在内部。这意味着即使外层函数已经执行完毕,闭包仍然可以访问和操作这些变量。
闭包有两个主要特点:
- 它可以访问和操作外层函数中的变量,即使这些变量在外层函数执行完毕后仍然存在。
- 闭包可以在其他地方被调用和使用,而不仅限于外层函数内部。
闭包常用于以下情况:
- 在函数内部定义一个函数,并将其返回,以便在外层函数执行完毕后仍可以访问和使用外层函数中的变量。
- 在异步编程中,用于保存异步回调函数中所需的变量状态,以便在回调函数执行时仍然可以访问这些变量。
2.闭包的使用
1.保持状态:
闭包可以用来保持函数的状态,而无需将变量放在全局作用域中。这对于需要记住某些状态的函数特别有用,例如计数器函数或者缓存函数。
def counter(): count = 0 def increment(): nonlocal count count += 1 return count return increment c = counter() print(c()) # 输出 1 print(c()) # 输出 2
2.回调函数:
闭包常用于创建回调函数,可以捕获并操作创建它们时的上下文,如事件处理程序或异步操作中的回调函数。
def make_multiplier(x): def multiplier(n): return x * n return multiplier times_3 = make_multiplier(3) print(times_3(5)) # 输出 15
3.私有变量:
闭包可以创建类似于私有变量的效果,通过在外部函数中定义变量并在内部函数中引用它们,可以隐藏变量并防止直接访问。
def make_counter(): count = 0 def counter(): nonlocal count count += 1 return count return counter c1 = make_counter() print(c1()) # 输出 1 print(c1()) # 输出 2 c2 = make_counter() print(c2()) # 输出 1 (每个闭包实例都有自己的作用域和状态)
4.注意事项
内存管理:使用闭包时需要注意内存管理,因为闭包函数保留了对外部作用域变量的引用,可能导致内存泄漏或不必要的资源占用问题。
可读性:尽管闭包非常强大,但过度使用闭包可能会使代码变得难以理解和维护。在选择使用闭包时,要权衡其带来的简洁性和代码可读性之间的平衡。
闭包是函数式编程中的重要概念,能够提供灵活性和可重用性,但在实际应用中需谨慎使用,避免引发意外的副作用和性能问题。
四,特殊变量global和nonlocal的使用
1.global关键字
global
关键字用于在函数内部声明一个变量是全局变量,即使在函数内部给变量赋值时也能影响到全局变量的值。通常情况下,函数内部的变量赋值会创建一个新的局部变量,不会影响到外部的同名全局变量。但是使用 global
关键字可以显式地告诉 Python 解释器,该变量是全局变量,需要在外部作用域中找到并修改它。
例如:
x = 0 def increment_global(): global x x += 1 increment_global() print(x) # 输出 1
在这个例子中,global x
声明了 x
是全局变量,而不是在 increment_global
函数内部创建一个新的局部变量 x
。
2.nonlocal关键字
nonlocal
关键字用于在函数内部声明一个变量来自于外部嵌套函数的作用域,而不是局部变量或全局变量。它主要用于闭包的情况,当一个函数内部定义了另一个函数,并且内部函数引用了外部函数的局部变量时,可以使用 nonlocal
来标识该变量来自于外部函数的作用域。
例如:
def outer(): y = 0 def inner(): nonlocal y y += 1 return y return inner func = outer() print(func()) # 输出 1 print(func()) # 输出 2
在这个例子中,nonlocal y
声明了 y
变量来自于外部函数 outer
的作用域,而不是在 inner
函数内部创建一个新的 y
变量。
总结
global
用于声明变量在整个程序中都可见,即全局变量。nonlocal
用于声明变量在封闭的嵌套函数作用域中可见,而不是局部变量或全局变量。
使用这两个关键字时要注意避免过度使用,因为它们可能会导致代码可读性和维护性降低,尤其是在复杂的嵌套函数结构中。
五,装饰器
1.何为装饰器
装饰器(Decorator)是Python语言中一种强大而灵活的特性,它允许在不改变代码结构的情况下,动态地修改函数或类的行为。装饰器本质上是一个函数,它接收一个函数或类作为输入,并返回一个新的函数或类。通过装饰器,我们可以在不修改原始对象(函数或类)的情况下,添加额外的功能、修改原有的行为或者进行包装。
2.装饰器如何定义
1.定义装饰器的基本步骤:
创建装饰器函数:装饰器本质上是一个函数,它接收一个函数作为参数,并返回一个新的函数或修改原来的函数,以实现额外的功能。
修改函数的行为:在装饰器函数内部,通常会定义一个内部函数,该内部函数执行额外的功能,然后调用原始函数。
应用装饰器:使用
@
符号将装饰器应用于目标函数或类。
2.装饰器的基本形式:
def decorator_function(original_function): def wrapper_function(*args, **kwargs): # 在调用原始函数之前可以添加额外功能 print(f"执行装饰器添加的额外功能,比如日志记录。") return original_function(*args, **kwargs) return wrapper_function # 应用装饰器的语法 @decorator_function def display(): print("显示函数被调用。") # 调用经过装饰的函数 display()
在这个例子中,decorator_function
是一个装饰器函数,它接收 display
函数作为参数,然后返回一个内部函数 wrapper_function
。在 wrapper_function
中,我们可以执行一些额外的功能,然后调用 original_function
,即 display
函数本身。
3.装饰器的基础用法
创建一个简单的装饰器
假设我们有一个简单的函数 say_hello()
,输出一句问候语:
def say_hello(): return 'Hello, World!'
现在,我们希望在每次调用 say_hello()
之前打印出函数名和调用信息。我们可以通过装饰器来实现这个需求。
步骤:
定义装饰器函数:创建一个装饰器函数,接受一个函数作为参数,并返回一个新的函数(通常是一个包装函数)。
包装函数:在装饰器函数内部定义一个包装函数,包装函数负责添加额外的行为,然后调用原始函数。
应用装饰器:使用
@
符号将装饰器应用到目标函数上。
实现装饰器:
def my_decorator(func): def wrapper(): print(f'Calling function: {func.__name__}') return func() return wrapper # 应用装饰器 @my_decorator def say_hello(): return 'Hello, World!' # 调用装饰后的函数 print(say_hello())
解释:
my_decorator(func)
是装饰器函数,它接受一个函数func
作为参数。- 在
my_decorator
内部,定义了一个名为wrapper()
的包装函数。 wrapper()
函数负责打印调用信息,然后调用原始的func()
函数。- 使用
@my_decorator
将装饰器应用到say_hello()
函数上。 - 当调用
say_hello()
时,实际上调用的是被装饰后的wrapper()
函数,从而实现了额外的行为。
输出结果:
Calling function: say_hello Hello, World!
通过这个简单的例子,你可以看到装饰器的基本作用:在不修改原函数代码的情况下,添加额外的功能或行为。在实际开发中,装饰器常用于日志记录、性能测试、权限验证等场景,使得代码更加清晰和易于维护。