程序创建, 访问, 改变一个变量时, 都是在一个保存该变量的空间内进行, 这个空间被称为命名空间, 即作用域
Built-in 内置
Global 全局变量
只作用于当前模块(可以理解为当前文件)
可以简单地理解为定以在函数外的变量就是全局变量, 如果在函数体定义那就时局部变量.
如何将局部变量变成全局变量?
使用global关键字
a = 1
def foo():
global a
a = 2
print(a)
foo()
print(a)Enclosed(嵌套) 自由变量
在嵌套函数中, 访问函数体之外的非全局变量
只作用于嵌套函数体
最大的应用就是闭包
自由变量是个相对的概念
将局部变量变成自由变量
使用nonlocal关键字
def make_averager():
total = 0
count = 0
def averager(value):
nonlocal total, count
total += value
count += 1
return total / count
return averager
my_avg = make_averager()
print(my_avg(1))
print(my_avg(2))Local局部变量
只作用于当前函数体
一旦变量在函数体中赋值, 那么该变量相对该函数来说就是局部变量
a = 1
b = []
def foo():
a = 2
b.append(2)
# 局部变量会在函数声明的时候就定义好
# 不是按照我们逻辑思维上先执行全局变量b.append(2), 然后再声明一个局部变量b
# 而是再函数声明之初就已经定义了b为局部变量
# b = 3
return None
foo()
print(a)
print(b)闭包
闭包指延申了作用域的函数, 也就是作用域中的Enclosed的概念
def make_averager():
series = []
def averager(value):
series.append(value)
total = sum(series)
return total / len(series)
return averager
# my_avg就是延申了作用域的函数
# series就是被延申作用域的变量
my_avg = make_averager()
print(my_avg(1))
print(my_avg(2))装饰器
实现原理
就是闭包, 延申了被装饰函数的作用域, 本质是将函数作为参数传递给一个可调用对象(函数或类)
目的
增加和扩展可调用对象(函数或类)的行为
实现一个装饰器
通过@关键字装饰函数
def clock_it_deco(func):
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
print(f"{func.__name__} execute time: {format(end_time - start_time, '.2f')} s")
return result
return wrapper
# @other_deco
@clock_it_deco
def foo(a, b):
count = 1
while True:
if count > a ** b:
break
count += 1
foo(10, 5)等同于
foo = clock_it_deco(foo)
foo(10, 5)