Python学习笔记-装饰器

一、作用域

简单说就是一个变量能够起作用的区域

python中除了模块,类,函数之外,其他如if/elif/else/try/except/while/for 并不能改变作用域

1.  全局作用域

一个模块(.py文件内部)有效

a = "hello world"     #全局变量
def func1(): 
    a = "hello python"     #局部变量
    print("a in func1 =", a)

func1()      #a in func1 = hello python
print("a in global =", a)           #a in global = hello world

如果要在函数内部使用全局变量,需要用global关键字

a = "hello world"     #全局变量
def func1(): 
    global a      #引用全局变量
    a = "hello python"     #对全局变量重新赋值
    print("a in func1 =", a)

func1()      #a in func1 = hello python
print("a in global =", a)        #a in global = hello python    

2. 局部作用域

只在某个区域内有效,如函数内部

def func1():
    i=1       #i是局部变量
    print(i)   #i能在函数内部(局部)使用,不会报错

print(i)    #在函数外使用i会报错: NameError: name 'i' is not defined

3. 嵌套作用域

嵌套一般是指一个函数嵌套另一个函数的情况,外层函数包含的作用域就是嵌套作用域

def outer():
    a = "hello world"  # 对于上层来说,是局部;对于下层来说,是嵌套

    def inner():
        a = "hello python"
        print("a in inner =", a)
    inner()
    print("a in outer =", a)

outer()
'''
a in inner = hello python
a in outer = hello world
'''

4. 内置作用域

python系统内固定模块里定义好的变量,我们直接使用,如print()

二、高阶函数

一切皆对象,函数跟字符串,列表等普通数据类型一样都是对象,函数名也一样是一个变量名

1. 将函数名赋值给其他变量

def func1():           #定义一个函数
    print('this is a function')
a=func1         #将函数名赋值给一个变量a
func1()         #this is a function    调用函数func1
a()             #this is a function    调用a,等于调用func1
print(id(func1))      #1422665511264
print(id(a))          #1422665511264 可以看出a和func1是一样的

2. 将函数名作为参数传递

def func1():            #定义一个函数
    print('this is a function')
def func2(func):        #定义一个函数,参数也是一个函数
    func()    #调用传递进来的函数名
func2(func1)     #this is a function

3. 将函数名作为其他函数返回值

def outer():        #定义一个函数
    def inner():    #在函数内部再定义一个函数
        print('this is a function')
    return inner    #将内部函数名返回
result=outer()      #调用外部函数,并用一个变量接收返回值,相当于result=inner
result()        #this is a function   因为返回值是内部函数名,加上()即调用内部函数相当于inner()

三、闭包

在一个内部函数里边,对在外部作用域(嵌套作用域,但不能是全局作用域)的变量进行引用,那么这个内部函数就被认为是闭包

def outer():
    x = 10
    def inner():
        print(x)     #引用在外部作用域(嵌套作用域)的变量
    return inner     #返回内部函数名,便于在外面访问该内部函数
result=outer()
result()      #10

四、装饰器

装饰器本质上是一个函数,该函数用来处理其他的函数,可以让其他函数在不需要修改代码的前提下,增加额外的功能,概括就是为已经存在的对象添加额外的功能,返回值是一个函数对象

对于如插入日志,性能测试,事务处理,缓存,权限校验等场景时,使用装饰器,可以抽离出与函数本身功能无关的相似代码并复用

例:有一个函数,需要在调用该函数时,执行函数原本功能并计算这个函数的执行时间

import time
def show_time(func):      #定义计算函数执行时间的函数,将函数名作为参数传递
    def inner():          #定义一个内部函数
        begin_time = time.time()  #将当前时间赋给变量
        func()                    #执行函数
        end_time = time.time()    #将当前时间赋给变量
        print("总计执行时间 =", end_time - begin_time)
    return inner          #返回内部函数

def func1():             #需要增加计算函数执行时间的原函数
    print("执行测试用例")
    time.sleep(1)             #因为函数执行太快,所以等待1s

func1 = show_time(func1)   #调用时间函数,并将返回值inner赋值给原函数名
func1()                    #调用原函数,但实际上是调用inner(),这样就让原函数不变的情况下,可以多执行时间的功能
'''
执行测试用例
总计执行时间 = 1.0077204704284668
'''

在上例中,func1是被装饰函数,show_time是装饰函数,也就是装饰器,但每次使用时都需要调用,赋值,比较麻烦,python中提供了一个语法糖使之更简单清晰

import time
def show_time(func):
    def inner():
        begin_time = time.time()
        func()
        end_time = time.time()
        print("总计执行时间 =", end_time - begin_time)
    return inner

@show_time     #语法糖,在被装饰函数前加上,实现代码要在之前 相当于func1=show_time(func1)
def func1():
    print("执行测试用例")
    time.sleep(1)

func1()

带参数的装饰函数

def outer(func):
    def inner(name):
        func(name)  # 需要保留被装饰函数原有的功能,所以通过传参的形式调用被装饰函数
        print("这是新加的功能")
    return inner

@outer
def func1(name):
    print("测试姓名:", name)

func1("张三")

带参数的装饰器

def wrap(age):
    def outer(func):
        def inner(name):
            func(name)  # 需要保留被装饰函数原有的功能,所以通过传参的形式调用被装饰函数
            print("这是新加的功能")
            print("年龄是:", age)
        return inner
    return outer

# wraper(18) 相当于 outer,@wraper(18) 相当于 @outer, @outer 相当于 func1 = outer(func1) = inner
@wrap(18)
def func1(name):
    print("测试订单:", name)

func1("张三")
'''
测试订单: 张三
这是新加的功能
年龄是: 18
'''
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值