python method decorate_Python 装饰器使用指南

本文详细介绍了Python装饰器的基础知识、何时执行、变量作用域、闭包以及装饰器的使用。装饰器在函数定义后立即执行,用于在不修改原函数代码的情况下增加额外功能。文中还探讨了闭包的概念,以及如何实现和使用装饰器,包括带参数的装饰器、类装饰器和内置装饰器如`@classmethod`、`@staticmethod`。同时,文章提供了装饰器实现缓存和统计执行次数等功能的示例。
摘要由CSDN通过智能技术生成

装饰器是可调用的对象,其参数是另一个函数(被装饰的函数)。

装饰器基础知识

首先看一下这段代码

def deco(fn):

print "I am %s!" % fn.__name__

@deco

def func():

pass

# output

I am func!

# 没有执行func 函数 但是 deco 被执行了

在用某个@decorator来修饰某个函数func时

@decorator

def func():

pass

其解释器会解释成下面这样的语句:

func = decorator(func)

其实就是把一个函数当参数传到另一个函数中,然后再回调,但是值得注意的是装饰器必须返回一个函数给func

装饰器的一大特性是,能把被装饰的函数替换成其他函数。第二大特性是,装饰器在加载模块时立即执行。

装饰器何时执行

装饰器的一个关键特性是,它们在被装饰的函数定义后立即运行。这通常在导入是(python 加载模块时)。

看下下面的示例:

registry = [] # registry 保存被@register 装饰的函数的引用

def register(func): # register 的参数是一个函数

print('running register(%s)' % func) # 打印被装饰的函数

registry.append(func) # 把 func 存入 `registery`

return func # 返回 func:必须返回函数,这里返回的函数与通过参数传入的一样

@register # `f1` 和 `f2`被 `@register` 装饰

def f1():

print('running f1()')

@register

def f2():

print('running f2()')

def f3(): # <7>

print('running f3()')

def main(): # main 打印 `registry`,然后调用 f1()、f2()和 f3()

print('running main()')

print('registry ->', registry)

f1()

f2()

f3()

if __name__=='__main__':

main() # <9>

运行代码结果如下:

running register()

running register()

running main()

registry -> [, ]

running f1()

running f2()

running f3()

从结果可以发现register 在模块中其他函数之前运行了两次。调用 register 时,传给它的参数是被装饰的函数(例如)。

看完上边的示例我们知道,函数被装饰器装饰后会变成装饰器函数的一个参数,那这时就不得不说变量的作用域了。

变量作用域

先看下下边这段代码:

def f1(a):

print(locals())

print(a)

print(b)

f1(3)

# output

{'a': 3}

3

Traceback(most recent call last):

File "", line 1, in

File "", line 3, in f1

NameError: global name 'b' is not defined

这里的错误是因为全局变量 b 没有定义,如果我们先在函数外部给 b 赋值,再调用这个方法就不会报错了。

函数运行时会创建一个新的作用域(命名空间)。函数的命名空间随着函数调用开始而开始,结束而销毁。

这个例子中 f1 的命名空间中只有 {'a': 3},所以 b 会被认为是全局变量。

再看一个例子:

b = 6

def f2(a):

print(a)

print(globals())

print(locals())

print(b)

b = 9

f2(3)

# output

3

{

'__name__': '__main__',

'__doc__': None,

'__package__': None,

'__loader__': <_frozen_importlib_external.sourcefileloader object at>,

'__spec__': None,

'__annotations__': {},

'__builtins__': ,

'__file__': '~/var_local.py',

'__cached__': None,

'b': 6,

'f2':

}

{'a': 3}

3

Traceback(most recent call last):

File "", line 1, in

File "", line 3, in f1

UnboundLocalError: local variable 'b' referenced before assignment

这个例子和上一个例子不同是,我现在函数外部定义了全局变量b,但是执行f2 这个方法并没有打印6,这是为什么呢?

这是因为执行函数时 Python 会尝试从局部变量中获取 b,函数对于已经引用但未赋值的变量并不会自动声明为局部变量,所以解释器发现后边的赋值之前有引用就会抛出 UnboundLocalError 错误。

Python 不要求声明变量,但是假定在函数定义体中赋值的变量是局部变量。

如果要让解释器把b当做全局变量,要使用global声明:

b = 6

def f3(a):

global b

print(a)

print(b)

b = 9

f2(3)

# output

3

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值