# -*- coding: utf-8 -*-
"""如果python中的一个类定义了 __call__ 方法,那么这个类它的实例就可以作为函数调用,也就是实现了 () 运算符,即可调用对象协议"""
print("========================__call__-test================================")
class myTest:
def __init__(self, x, y):
self.x = x
self.y = y
def __call__(self, x, y):
self.x, self.y = self.x+x, self.y+y
a = myTest(1, 2)
a(4, 5)
print(a.x, a.y)
#>>>5
#>>>7
print("========================__call__-test=================================\n")
print("========================类(class)做装饰器-1-test==================================")
"""修饰器"""
class myDecoratorsTest:
def __init__(self, func): #构造函数的参数为下面定义的函数
print("myDecoratorsTest __init__ ####1####") #1
self.func = func
def __call__(self, *args, **kwargs):
print("myDecoratorsTest __call__ ####2####")
result = self.func(*args, **kwargs)
return result
@myDecoratorsTest
def add_num(x, y):
print("add_num ####3####")
return x + y
#dt = myDecoratorsTest(add_num)
#dt(1,2)
print(add_num(1, 0))
#>>>1
print("========================装饰器-1-test==================================\n")
print("=======================【第一次修改】==================================")
print("========================装饰器-2-test==================================")
#装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能.装饰器的作用就是为已经存在的对象添加额外的功能
def fun_A(fun):
print('A')
fun()
def fun_B():
print ('B')
return 1
fn = fun_A(fun_B)
print(fn) #因为没有返回值所以是None
#>>>A
#>>>B
print("-----------------------------------------------------------------------")
#可以看出,这个程序的运行过程为:
#1.执行函数fun_A,把fun_B当作参数传进去, fun() 这一句 执行了 fun_B, 然后打印 'B' , 返回 1
#2. print ('B') 这一句把 返回的 B 打印出来
#而修饰器的作用:
def fun_AA(fun):#函数本身也是对象,所以可以将函数作为参数传入另一函数并进行调用,而funB是有返回值的,所以结果输出了返回值1.(个人理解)
print('AA')
n = 1
print(fun(n))
@fun_AA
def fun_BB(n):
print('BB')
return n+1
#fn = fun_BB
#作用相当于 fn = fun_AA(fun_BB),不过只能放在一个函数或者类定义之前
#需要注意的是,如果fun_BB在fun_AA里没用被调用的话,那fun_BB是不会被执行的,如:
def fun_AAA(fun):
print ('AAA')
@fun_AAA
def fun_BBB():
print ('BBB')
return 1
#>>>AAA
#可以看出,只执行了fun_AAA而fun_BBB没有被执行,因为print('BBB')并没有被打印出来.
#ps:如果fun_AAA不加参数的话,比如直接 def funAAA(): 这样定义,他是会报错的:
#@fun_AAA
#TypeError: fun_AAA() takes 0 positional arguments but 1 was given
#大意是@fun_AAA中的fun_AAA必须要给他提供一个参数,但是你给了0个.
print("========================装饰器-2-test==================================\n")
print("=======================【第二次修改】==================================")
#第一次了解的是一些浅层次的东西,把它深入一下,看个例子:
print("========================一层装饰: 例子==================================")
def outter(func):
print('---正在装饰-outter---')
def inner():
print('---outter-inner---')
func()
return inner
@outter
def test1():
print('---test1---')
test1()
#>>>正在装饰
#可以看出,装饰器 @w1 这一行,其实在函数没有被调用之前已经执行了, 这一句就等于 f1=w1(f1) 所以 w1 函数已经被调用了,返回的是 cou函数的引用,
#所以说如果再调用 f1() ,其实执行的是 cou() ,而真正的 f1 函数的引用现在正被保存在 w1 函数中的 func参数里面,
#(这儿可以当作闭包的一个表现,即当函数中有东西外边还有引用指向它的时候,它并不会立即回收,而是保存了这个函数的空间)
print("\n========================二层装饰: 例子==================================")
def outer1(func):
print("---正在装饰-outer1----")
def inner():
print("---outer1-inner----")
func()
return inner
def outer2(func):
print("---正在装饰-outer2----")
def inner():
print("---outer2-inner----")
func()
return inner
@outer1
@outer2
def test2():
print("---test2---")
#>>>---正在装饰-outer2----
#>>>---正在装饰-outer1----
#从运行结果可以看出,首先调用装饰器 outer2,再调用装饰器 outer1,也就是说 运行到 @outer1 这一行,因为在它下面的并不是一个函数,所以 outer1 先暂停,先调用 outer2,
#outer2 装饰完成之后,返回的是 outer2 的 inner 函数的引用,
#outer1 再开始对 outer2 的inner 函数进行装饰. 最后返回的是 outer1 的 inner 函数.
# 如果最后调用 test2() 那么运行结果为:
test2()
# 因为 这个时候调用 test2() 其实 调用的是 outer1 的 inner 函数,所以首先打印 ---outer1-inner---- ,
# 然后 执行 func() 这个 func() 也就是 outer2 的inner, 所以再打印 ---outer2-inner----,
# 下一句 fun() 才是真正的 test2() 函数,打印 ---test2---
print("\n========================装饰有参数的函数: 被装饰的函数有参数的话,可以这样:==================================")
def outer3(func):
print("---正在装饰-outer3----")
def inner(*args, **kwargs):
print("---outer3-inner----")
func(*args, **kwargs)
return inner
@outer3
def test3(a):
print("---test3-a=[%d]---" % a)
test3(123)
#>>>---正在装饰-outer3----
#>>>---outer3-inner----
#>>>---test3-a=[123]---
#在 inner 函数里面加上 接受无名参数和关键字参数,然后 func(*args, **kwargs) 把接收到的参数原封不动的传回 test3 函数里面去,这样 test3 无论有多少个参数,都可以给他传回去.
#那么,如果被装饰的函数有返回值,同样,在 inner里面把函数返回的东西用个变量保存起来,然后 在inner 里面return 即可:
print("\n========================被装饰的函数有返回值:==================================")
def outer4(func):
print("---正在装饰-outer4----")
def inner(*args, **kwargs):
print("---outer4-inner----")
result = func(*args, **kwargs) # <----------------------
return result # <----------------------
return inner
@outer4
def test4(a):
print("---test4-a=[%d]---" % a)
return a+a,456
res,res2=test4(123)
print(res)
print(res2)
#可以看出 res res2 成功保存了返回的结果
print("\n========================装饰器进行调用,如 @outer5() 后面带个括号=装饰器没有参数==================================")
#如果,对装饰器进行调用,如 @outer5() 后面带个括号, 结果会怎样:
def outer5():
print("---正在装饰-outer5----")
def inner(func):
print("---outer5-inner----")
return inner
@outer5()
def test5():
print("---test5---")
#>>>---正在装饰-outer5----
#>>>---test5----
#test5() #Traceback TypeError 'NoneType' object is not callable
#可以看出,虽然没有调用 test5,但是竟然连里面的inner函数也被执行了一遍,因为输出了 ---outer5-inner----
# ,这说明,如果 @outer5() 这样用 ,那么它首先会 把 outer5() 函数执行一遍 , 这个时候返回的是 inner 函数的引用,
#那么,@outer5() 就变成了 @inner 这个时候 再把 test5 传到了inner函数里面开始进行装饰 所以 inner 函数被执行,
print("\n========================装饰器带括号()=并且带有参数==================================")
#利用这个特点,可以在 装饰器中带有参数 ,只不过为了防止调用,需要在外面再加上一层:
def outer6(param1,param2):
print("---正在装饰-outer6----")
print("---outer6----[%s]-[%s]" % (param1, param2))
def outer6_1(func):
print("---正在装饰-outer6_1----")
def inner():
print("---outer6_1-inner----[%s]-[%s]" % (param1,param2))
func()
return inner
return outer6_1
@outer6('param1',"param2")
def test6():
print("---test6---")
#>>>---正在装饰1----
#过程 1. 首先执行 outer6('hello~') outer6里面用 nihao 这个变量保存传递的参数,返回的是 outer6_1 的引用
# 2. 装饰器那一行 变成了 @outer6_1 ,然后把 test6 传递进去,调用 outer6_1 开始进行装饰
# 3. 装饰完成后 返回的 是 inner 的引用 所以 现在 test6 = inner
#如果调用 test6() 则正常执行,还可以在 inner 中把传递进去的参数打印出来:
test6()
python之装饰器讲解***
最新推荐文章于 2023-01-15 13:13:07 发布