使用
()
调用函数时,主要发生的事情包括查找函数对象、创建调用帧(包含了函数的局部变量和执行环境等信息)、参数传递、执行函数体和返回值(如果函数没有显式地返回值,它会隐式地返回None
)这一过程使得我们能够动态调用和执行函数
函数式编程
代码重用
闭包
基本概念
闭包(Closure)是指一个函数内部定义的函数,并且这个内部函数能够引用外部函数中的变量,即使外部函数已经执行完毕。
特点:
嵌套函数:闭包必须有一个内部函数
自由变量:内部函数使用外部函数的变量
返回内部函数:外部函数返回内部函数的引用
inner_function
就是一个闭包,因为它引用了外部函数outer_function
的变量message
正常来说,调用一个函数的时候,这个函数中的所有局部变量和形参,都只会在这个函数执行的过程中才会保留,只要这个函数执行完毕,这些局部变量和形参就会被自动释放,也就是没有了。
闭包比普通函数强大的地方在于,它在外部函数执行完毕之后,这个外部函数中的所有局部变量和形参,都不会被释放,而是等到内部函数执行完毕,以便于调用内部函数的时候可以使用。
好处:可以将局部变量永久存储
坏处:占用内存
普通函数:
[A() for i in range]
循环一次 释放一次,100次也只有一次的A()数据闭包函数:
[B() for i in range]
数据一直保存在内存中,每次循环都会创建新的 保存下来
def outer_function(msg):
message = msg
def inner_function():
print(message)
return inner_function
closure = outer_function("Hello, World!")
closure()
nonlocal
在嵌套函数中修改外部非全局变量。它告诉Python解释器,在当前作用域内寻找该变量,而不是在局部作用域内定义一个新变量
def outer_function():
count = 0
def inner_function():
# 表示 count 不是局部变量,而是外部函数 outer_function 中的变量
# 每次调用 inner_function 时,它都会修改 outer_function 中的 count 变量
nonlocal count
count += 1
print(count)
return inner_function
closure = outer_function()
closure() # 输出: 1
closure() # 输出: 2
closure() # 输出: 3
多个内部函数
一般还是只写一个内部函数
def counter_operations(initial_count):
count = initial_count
def increment():
nonlocal count
count += 1
return count
def decrement():
nonlocal count
count -= 1
return count
return increment, decrement
# 创建闭包
increment_func, decrement_func = counter_operations(10)
# 使用闭包
print(increment_func()) # 输出: 11
print(increment_func()) # 输出: 12
print(decrement_func()) # 输出: 11
print(decrement_func()) # 输出: 10
外部函数变量
闭包中,外部函数的变量,不会被立即销毁(便于内部函数调用)
可以重复使用外部函数变量,或者是不断覆盖,不断使用 赋值 之后的外部函数变量
def create():
# 定义坐标原点
pos = [0, 0]
def player(direction, step):
# 这里的pos是全局变量, new_x,new_y是局部变量,局部变量会覆盖全局变量
new_x = pos[0] + step * direction[0]
new_y = pos[1] + step * direction[1]
# 外部函数中的变量,不会立即销毁,这里用new_x/new_y覆盖了 外部函数的变量
# 下一次进入函数的时候,使用的就是 外部函数中的变量,值 却是上一次修改的值
pos[0] = new_x
pos[1] = new_y
return pos
return player
player = create() # 返回的是 player 函数
print(player([1, 0], 10))
print(player([0, 1], 20))
print(player([-1, 0], 20))
装饰器
装饰器(Decorator)是一种高级函数,用于在不改变函数本身的情况下,扩展或修改其功能
装饰器本质上是一个返回函数的函数
装饰器通过使用@decorator_name
语法来应用
示例:
def decorator_function(original_function):
def wrapper_function(*args, **kwargs):
print(f"Wrapper executed this before {original_function.__name__}")
return original_function(*args, **kwargs)
return wrapper_function
@decorator_function
def display():
print("Display function ran")
display()
@decorator_function
是装饰器,它会修改display函数的行为,使其在执行原始函数之前打印一条信息
无参数
def decorator(func: Callable):
def wrapper(*args, **kwargs):
print('before')
func(*args, **kwargs)
print('after')
return wrapper
@decorator
def double(x: int):
print(f"func: {x * 2}")
duble(10)
before
func: 20
after
有参数
ıdef repeat(num_times):
def decorator_repeat(func):
def wrapper(*args, **kwargs):
for _ in range(num_times):
func(*args, **kwargs)
return wrapper
return decorator_repeat
@repeat(num_times=3)
def greet(name):
print(f"Hello, {name}!")
greet("Alice")
Hello, Alice!
Hello, Alice!
Hello, Alice!
def my_decorator(arg1, arg2):
def decorator(func):
def wrapper(*args, **kwargs):
print("在原函数前执行,参数为:", arg1, arg2)
result = func(*args, **kwargs)
print("在原函数后执行,参数为:", arg1, arg2)
return result
return wrapper
return decorator
@my_decorator("hello", "world")
def say_hello(name):
print(f"{name}!")
say_hello("Tom")
在原函数前执行,参数为: hello world
Tom!
在原函数后执行,参数为: hello world
注意事项
装饰器的执行顺序是从内到外,即先执行最内层的装饰器,再执行外层的装饰器
装饰器可以用于类方法、静态方法等,但通常用于普通函数
from typing import Callable
def duble(x: int) -> None:
"""
Python中的函数,其实是用一个变量,里面保存了一个函数对象
"""
print(x * 2)
def tripele(x: int):
"""三倍"""
return x * 3
def call_num(func: Callable, num: int):
"""
调用一个函数
这里是把传进来的参数,带到func里面去执行,那么func里面只需要拿着这个参数,去操作就可以了
如果有返回值,我们再用变量去接收这个变量
我们可以直接打印func(num),但是其返回值是None,是因为我们再func里面没有返回任何东西,Python就默认返回None了
如果func里面返回数据了,我们就可以接受这个数据,如tripele()
"""
func(num)
result = func(num)
return result
# call_num(duble, 10)
result = call_num(tripele, 20)
print(result)
#####################################################
def get_multiple_func(num):
"""这里返回的是一个函数应用"""
def multiple(x: int) -> int:
"""在这里操作了变量"""
return x * num
return multiple
double = get_multiple_func(2)
triple = get_multiple_func(3)
print(double(10))
print(triple(10))
两者比较
装饰器通常利用闭包来实现
装饰器的内部函数(wrapper function)引用了装饰器外部函数的变量(如原始函数),从而形成闭包
闭包:用于保存函数的环境,使得内部函数可以记住和访问外部函数的变量
装饰器:用于动态地修改或扩展函数的行为,通常通过闭包实现
评论区