Python函数之装饰器与闭包
(一) 函数的变量作用域与闭包
这里是个人理解:python闭包一般用出现内嵌套函数中,其实大多数我们不知不觉用过它,只不过不知道这个概念。首先我们都知道函数内部的变量都有自己的作用域,在外层函数内一旦给变量绑定了对象,如果这个对象是不可变的如数字、元组,那么它的作用域只能在外层函数中,这就是局部变量,我们在没有声明的情况下,不能在内层函数赋值;同理内层函数也是。那可变对象如列表呢?我们可以通过pop()方法或append()在内层函数修改列表元素,而不需要赋值,看下例子:
import numpy as np
def test():
list0 = []
def test2():
for i in range(4):
list0.append(np.random.randint(low=i,high=10,size=1))
print(list0)
return test2()
x = test()
输出结果:
[array([2]), array([3]), array([6]), array([5])]
虽然不可以在内层函数内直接队外层局部变量进行赋值,但是我们可以声明其为自由变量:关键字nonlocal
基本语法:
#def 外部函数名(参数):
# 外部变量
# def 内部函数名():
# 使用外部变量
# return 内部函数名
eg:
def make_averager():
count = 0
total = 0
def averager(new_value):
nonlocal count,total#,由于外部变量被绑定在内存中,且该变量非可变对象,不能更新,所以需要声明是自由变量,允许更新
count += 3
total += new_value
return total/count
return averager #不用加括号,因为是把内部函数当做变量(函数名)返回
y = make_averager()
print(y(5))
输出结果:
1.6666666666666667
(二)函数装饰器
基本语法
# def 函数装饰器名称(func):
# def 内嵌套函数():
# 需要添加的新功能
# return func
# @ 函数装饰器名称
# def func(参数):
# 函数体
# 函数调用:func(参数)
eg1:
def decorate(func):#定义函数装饰器
def newfunc(x):#新的函数,该函数的参数是通过旧函数传给的,所以引用旧函数必须有一个参数
x += 2
print(x)#新功能
print(newfunc.__name__)
print(func.__name__)#新功能
return func()#返回旧功能,这里不能有参数,因为是调用旧函数,而旧函数是没有参数传入的
return newfunc
@decorate
def func1():
print("函数1")
return("func 1")
@decorate
def func2():
y = 0
y += 1
print(y)
print(func1(3))#实际上这里并非一般的函数调用,而是调用的新函数,用一个词形容就是名存实亡,参数3也不是传给func1的
func2(5)#同上
#print(newfunc.__name__)这里之所以不能显示出函数名,是因为该函数的定义空间在外层函数即装饰器内,而不在最外层
输出结果:
5
newfunc
func1
函数1
func 1
7
newfunc
func2
1
eg2:
def fun1(ff):
def fun2(y):
return ff(y) + 100
return fun2
@fun1
def ff(y):
return y*y
def filterarg(x):
def fit(*args):
if len(args) == 0:
return 0
for i in args:
if not isinstance(i,int):
return 0
return x(*args)
return fit
@filterarg
def sums(*args):
return sum(args)
@filterarg
def average(*args):
return sum(args)/len(args)
print(sums(3,4,5))
输出结果:
12
print(filterarg(average)(3,4,5))
输出结果:
4.0
几个常用的装饰器:
@property、@classmethod、@staticmethod
class Rectangle():
def __init__(self,width,height):
self.width = width
self.height = height
@property
def area(self):
return self.width*self.height
@staticmethod#静态方法,既可以被类调用,也可以被实例调用
def fun():
return 'XXXXX'
@classmethod#类方法,只可以被类调用,类似的还有__new__
def show(cls):
print(cls)
return 'YYYY'
c1 = Rectangle(3,4)
print(c1.area)#经过property修饰后方法area不再是可调用对象,而成为实例属性
print(Rectangle.fun())
print(Rectangle.show())
参考文献:《python进阶》