python反射、闭包、装饰器_Python(十四、闭包和装饰器)

闭包

def test(x, y):

def t1(z):

return x * z + y

return t1

t = test(2, 3)

print(t(3))

print(t(4))

闭包修改外部外部嵌套函数的变量值

# 错误案例

def test():

msg=10

def t1():

print("%d"%msg)

msg=100

print("%d" % msg)

return t1

t = test()

t()

"""

此时,第一个msg不会输出10而是直接报错,因为python会认为

t1函数扫描发现下面定义的有msg,类似于声明提升,但是没赋值,所以不允许使用

如果想使用,加上nonlocal,如下面的案例

"""

# nonlocal适用于嵌套函数中内部函数修改外部变量的值(该属性python3专用)

def counter(start=0):

def incr():

nonlocal start

start += 1

return start

return incr

c1 = counter(5)

print(c1())

print(c1())

c2 = counter(50)

print(c2())

print(c2())

print(c1())

print(c1())

print(c2())

print(c2())

python2等效案例

def counter(start=0):

count=[start]

def incr():

count[0] += 1

return count[0]

return incr

c1 = closeure.counter(5)

print(c1()) # 6

print(c1()) # 7

c2 = closeure.counter(100)

print(c2()) # 101

print(c2()) # 102

装饰器

基本案例

def t1(func):

print("装饰器的装饰过程是在代码加载的时候就执行的")

def t2():

return func

return t2

@t1

def T():

print("t执行")

return "haha"

t = T()

print(t())

"""

执行的结果:

装饰器的装饰过程是在代码加载的时候就执行的

t执行

haha

说明:第一句输出,即使在t=T()没写的情况下也会执行,是解释器的自主行为

"""

装饰器的基本原理(闭包)

def t1(func):

def t2():

return func

return t2

def T():

print("t执行")

return "haha"

T = t1(T)

t = T()

print(t())

"""

执行的结果:

t执行

haha

"""

综上所述,案例一的T()相当于案例二的T=t1(T)

多装饰器装饰同一个函数

def t1(func):

print("t1初始化")

def t2():

print("t2执行")

func()

return t2

def t3(func):

print("t3初始化")

def t4():

print("t4执行")

func()

return t4

@t3

@t1

def T():

print("T执行")

t = T()

"""

执行的结果:

t1初始化

t3初始化

t4执行

t2执行

T执行

说明:初始化是解释器从上到下,所以到@t3时候,进行装饰,但是装饰必须先有函数传入(联想闭包)

所以肯定先去获取函数,所以执行到@t1,所以t1初始化先执行

但是装饰完毕之后,代码在一个内存中合并起来,是从上倒下的,所以t4先执行

"""

被装饰器的函数有参数

def t1(func):

def t2(a, b):

print("t2执行")

func(a, b)

return t2

@t1

def T(a, b):

print("T执行", a, b)

T(1,2)

"""

执行的结果:

t2执行

T执行 1 2

"""

被装饰的函数有不定长参数

def t1(func):

def t2(*args, **kwargs):

func(*args, **kwargs)

return t2

@t1

def T(*args, **kwargs):

print("T执行", args,kwargs)

T(1,2,3,num=10)

"""

执行的结果:

T执行 (1, 2, 3) {'num': 10}

"""

带参数的装饰器

def t0(msg="hello"):

def t1(func):

def t2(*args, **kwargs):

func(*args, **kwargs)

print(msg)

return t2

return t1

@t0("zengqiang")

def T(*args, **kwargs):

print("T执行", args, kwargs)

T(1, 2, 3, num=10)

"""

执行的结果:

T执行 (1, 2, 3) {'num': 10}

zengqiang

总结:带参数的装饰器,比一般装饰器要多一层函数定义

"""

类装饰器(扩展)

装饰器函数其实是这样一个接口约束,它必须接受一个callable对象作为参数,然后返回一个callable对象。在Python中一般callable对象都是函数,但也有例外。只要某个对象重写了 call() 方法,那么这个对象就是callable的

class Test():

def __call__(self):

print('call me!')

t = Test()

t() # call me

类装饰器

class Test(object):

def __init__(self, func):

print("---初始化---")

print("func name is %s"%func.__name__)

self.__func = func

def __call__(self):

print("---装饰器中的功能---")

self.__func()

#说明:

#1. 当用Test来装作装饰器对test函数进行装饰的时候,首先会创建Test的实例对象

# 并且会把test这个函数名当做参数传递到__init__方法中

# 即在__init__方法中的属性__func指向了test指向的函数

#

#2. test指向了用Test创建出来的实例对象

#

#3. 当在使用test()进行调用时,就相当于让这个对象(),因此会调用这个对象的__call__方法

#

#4. 为了能够在__call__方法中调用原来test指向的函数体,所以在__init__方法中就需要一个实例属性来保存这个函数体的引用

# 所以才有了self.__func = func这句代码,从而在调用__call__方法中能够调用到test之前的函数体

@Test

def test():

print("----test---")

test()

showpy()#如果把这句话注释,重新运行程序,依然会看到"--初始化--"

"""

运行结果如下:

---初始化---

func name is test

---装饰器中的功能---

----test---

"""

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值