python装饰器与闭包

python装饰器与闭包

闭包= 内部函数+外部环境

def outer(x):
    def inner():
        print(x+9)
    return inner

inner = outer(10)
inner()

正常情况下,L-E-G-B原则,inner()作为内部函数,处于L级别local应无法调用上一层级的变量(作用域不同),在满足闭包的情况下,可以直接调用;

什么类型的语言可以使用装饰器?:所有函数可以作为参数传递的语言均可以使用装饰器!!!
装饰器的开放封闭原则:对扩展开放,对修改封闭!!!
源代码为:

def foo():
    x = 0
    for i in range(10000000):
        x += 1
    print(x)
foo()

此时需要将源代码扩展,增加计算此函数运行所需时间,不考虑装饰器的情况下:

import time
def foo():
    startTime = time.time()
    x = 0
    for i in range(10000000):
        x += 1
    print(x)
    endTime = time.time()
    print("useTime:%s"%(endTime-startTime))
foo()

或:

import time
def foo():

    x = 0
    for i in range(10000000):
        x += 1
    print(x)


def show_time(f):
    startTime = time.time()
    f()
    endTime = time.time()
    print("useTime:%s" % (endTime - startTime))

show_time(foo)

在各大公司,当一个函数被大量调用后,无法得知,此函数是否被其他人员调用,因此,对于已经实现的函数功能,不可对源码进行更改,即“开放封闭原则“,故需要使用到装饰器:

import time
def foo():
    x = 0
    for i in range(10000000):
        x += 1
    print(x)

def show_time(f):
    def inner():
        startTime = time.time()
        f()
        endTime = time.time()
        print("useTime:%s" % (endTime - startTime))
    return inner

foo = show_time(foo)
foo()

使用闭包,内部函数调用外部变量,再将函数赋值,按原函数调用时,就会执行闭包中的内部函数,以此调用原函数,达到不改变原函数与调用方式,做到扩展原来功能的要求。
python默认将foo = show_time(foo)代码使用@表示:

import time

def show_time(f):
    def inner():
        startTime = time.time()
        f()
        endTime = time.time()
        print("useTime:%s" % (endTime - startTime))
    return inner

@show_time    #foo = show_time(foo)
def foo():
    x = 0
    for i in range(10000000):
        x += 1
    print(x)

foo()

装饰器的作用即为,在引用函数时,将原调用函数执行红色部分变动为执行蓝色部分
装饰器
补充一段简单的装饰器代码,仅供参考:

loginStatus = False
loginStatus2 = False
def login(choose_type):
    def type(func):
        if choose_type == 1:
            def inner():
                global loginStatus
                if loginStatus == False:
                    name = input("请输入账号:")
                    passwd = input("请输入密码:")

                    f = open("login_list", 'r', encoding='utf8')
                    data1 = f.read()
                    data2 = eval(data1)
                    f.close()
                    if name in data2:
                        if passwd == data2[name]:
                            print("welcome".center(40,"#"))
                            loginStatus = True
                            func()
                        else:
                            print("no such name or password")
                    else:
                        print("no such name or password")
                else:
                    func()
            return inner
        elif choose_type == 0:
            def inner():
                global loginStatus2
                if loginStatus2 == False:
                    name = input("请输入账号:")
                    passwd = input("请输入密码:")
                    data2 = {"xin":"123456"}
                    if name in data2:
                        if passwd == data2[name]:
                            print("welcome".center(40, "#"))
                            loginStatus2 = True
                            func()
                        else:
                            print("no such name or password")
                    else:
                        print("no such name or password")
                else:
                    func()

            return inner
    return type
@login(1)
def home():
    print("welcome to home")

@login(0)
def finance():
    print("welcome to finance")
@login(1)
def book():
    print("welcome to book")


while True:
    print("""
    1、home
    2、finance
    3、book
    """)
    choose = input(">>>")
    if choose.isdigit() and int(choose)>0 and int(choose)<4:
        choose = int(choose)
        if choose == 1:
            home()
        elif choose == 2:
            finance()
        elif choose == 3:
            book()
    else:
        print("no such page")
  • 补充知识点:有关原函数的元信息查看。

    # 对于一般装饰器使用,在执行过程中无法调用原函数的元信息‘__doc__,__name__,__dict__ 等’
    import time
    
    def show_time(f):
        def inner(*args):
        	'''
        	*args : 装饰器引入参数
        	'''
            startTime = time.time()
            f(*args)
            endTime = time.time()
            print("useTime:%s" % (endTime - startTime))
        return inner
    
    @show_time    #foo = show_time(foo)
    def foo(a):
        '''
        a : aaaaa
        '''
        x = 0
        print(a)
        for i in range(10000000):
            x += 1
        print(x)
    
    foo('22')    # 22 10000000 useTime:0.4469478130340576
    # 此处查看__doc__调用的是装饰器的内置函数的元信息 故显示 *args : 装饰器引入参数
    print(foo.__doc__) #  *args : 装饰器引入参数
    

    以下做法可以使装饰器也可查阅原函数的元信息

    import time
    import functools
    
    def show_time(f):
    	# 引入内置函数 functools.wraps 将调用装饰器的函数作为参数传入,即可复制调用装饰器的原函数的元信息,此时装饰器可查看原函数元信息
        @functools.wraps(f)
        def inner(*args):
        	'''
        	*args : 装饰器引入参数
        	'''
            startTime = time.time()
            f(*args)
            endTime = time.time()
            print("useTime:%s" % (endTime - startTime))
        return inner
    
    @show_time    #foo = show_time(foo)
    def foo(a):
        '''
        a : foo函数的传入参数
        '''
        x = 0
        print(a)
        for i in range(10000000):
            x += 1
        print(x)
    
    foo('22') 		# 22 10000000 useTime:0.4469478130340576
    # 此处显示的为装饰器复制的原函数的元信息,起到便捷作用,提升代码的可读性
    print(foo.__doc__)  # a : foo函数的传入参数
    
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值