
本文共 3600 字,大约阅读时间需要 12 分钟。
在python中,函数可以作为参数传递。装饰器可以很方便的给原函数增加一些功能。使用装饰器必须和内嵌包装函数一起。在f2上@f1等价于执行f2 = f1(f2)。注意这里是f2而不是f2(),也就是说是函数名作为参数传递,不需要执行f2();而f1是f1(),所以f1在使用装饰器的地方相当于调用过一次。如果f1是一个类,那么相当于这里要调用一次构造函数__init__和回调函数__call___。
单纯嵌套
def f1(g): print("in f1") return g@f1def f2(): print("in f2")f2()f2()
在这个例子中@f1等价于f2 = f1(f2)= f2,此时打印了"in f1";接着执行两遍f2()就是打印两遍"in f2"。最终输出为:
in f1in f2in f2
内嵌包装函数,保证装饰器调用
def f1(g): print("in f1") def m(): print("in m") return g() return m@f1def f2(): print("in f2")f2()f2()
在这个例子中@f1等价于f2 = f1(f2)= m,此时打印了"in f1";接着执行两遍f2()等价于执行m(),而m()返回f2()。因此返回了两遍"in m in f2"。最终输出为:
in f1in min f2in min f2
装饰器带参数,需要两层内嵌函数
def f1(arg): print("in f1") def m(g): print("in m") def n(): print(arg) print("in n") return g() return n return m@f1("para")def f2(): print("in f2")f2()f2()
在这个例子中@f1(“para”)等价于f2 = f1(“para”)(f2)=m(f2)=n,此时打印了"in f1 in m";注意n()返回g(),因此接着执行两遍f2()等价于执行两遍n()+g()。这个例子用了2层包装函数,最终输出为:
in f1in mparain nin f2parain nin f2
函数带参数,需要使用args列表
def f1(func): print("in f1") def m(a, b): print("in m") print(func(a, b)) return m@f1def f2(a, b): print("f2(%s,%s) called." % (a, b)) return a + bf2(1, 2)f2(3, 4)
这里,@f1表示f2=f1(f2)=m,因此f2(a,b)=m(a,b)。如果参数列表个数不确定怎么办?那就需要用到*args或者**kargs了,前者将参数打包成tuple,后者打包成dict。下面是个例子:
def f1(func): print("in f1") def m(*args): print("in m") print(args) print(func(*args)) return m@f1def f2(a, b): print("f2(%s,%s) called." % (a, b)) return a + b@f1def f3(a, b, c): print("f3(%s,%s,%s) called." % (a, b, c)) return a + b + cf2(1, 2)f3(3, 4, 5)
返回:
in f1in m(1, 2)f2(1,2) called.3in m(3, 4, 5)f3(3,4,5) called.12
类作为装饰器
class f1: def __init__(self,para): self.para = para print("in __init__") def __call__(self,p): print ("in __call__") def m(): print("in m") return p(self.para) return m@f1("parameters")def f2(s): print(s) print ("in f2")f2()f2()
在这里,@f1(“para”) 等价于f2= f1(“para”)(f2)=m,先执行f1的构造函数和回调函数。注意m返回f2(“para”),因此执行两遍f2()变为执行两遍m()+f2(“para”)[[注:实际代码可能存在错误,建议仔细检查]]
回调函数和闭包
回调函数和闭包是python中非常重要的概念。回调函数是在每次调用类的时候启动,可以使实例像函数一样调用,比如f1是类f的一个实例,那么f1(a,b)等于f1.call(a,b)。
闭包指的是当某个函数被当成对象返回时,夹带了外部变量,就形成了一个闭包。简单来说,当定义内部嵌套函数时,返回的函数参数会自动定义__closure__属性,里面定义了一个元组用于存放所有的外面变量。
最简单的闭包例子
def f(a,b): def m(): return a+b return ma = f(4,5)for c in a.__closure__: print(c.cell_contents)
f中嵌套了函数m,因此返回函数赋值给a后,有了__closure__参数列表,其值等于内部函数m引用的外部函数f的参数列表的值,结果为:
45
装饰器和闭包
def f1(g): def m(): print("in m") return g() return m@f1def f2(): print("in f2")print(f2.__closure__[0].cell_contents)
@f1等价于f2 = f1(f2)=m,因此f2.closure[0]的值是原始的f2函数。最后输出:
in f2
带参数的装饰器和闭包
def f1(arg): def m(g): def n(): k = arg return g() return n return m@f1("para")def f2(): print("in f2")print(f2.__closure__[0].cell_contents)print(f2.__closure__[1].cell_contents)
这里n是最内部嵌套函数,形成了一个闭包。@f1(“para”)返回n的__closure__函数包含了arg和g两个参数。上面的例子输出为:
in f2para
回调函数和闭包
class f1: def __init__(self,para): self.para = para def __call__(self,p): def m(): return p(self.para) return m@f1("parameters")def f2(s): print(s) print ("in f2")print(f2.__closure__[0].cell_contents("abc"))print(f2.__closure__[1].cell_contents.para)
f1在回调的时候包含了嵌套函数,因此在执行f2= f1(“para”)(f2)的时候,传入了p和self两个参数(注意p在前面),因此输出为:
abcin f2parameters
发表评论
最新留言
关于作者
