python入门day11闭包&装饰器

闭包

def func():
    a=100

    def inner_func():
        b=99
        print(a,b)
    return a

# print(a)
# inner_func()

x=func()#100  并没有调用到inner_func()
print(x)

#闭包
#在函数中提出得概念
def func2():
    a=100

    def inner_func():
        b=99
        print(a,b)
    return inner_func #注意不要加上括号

# print(a)
# inner_func()

x=func2()#100  并没有调用到inner_func()
print(x)#<function func2.<locals>.inner_func at 0x000001E579519048>
x()#100 99
#x就是内部函数,加上()就可以调用这个函数

'''
闭包的条件:
1.外部函数中定义了内部函数
2.外部函数是有返回值的
3.返回的值是:内部函数名
4.内部函数引用了外部函数的变量
格式:
def 外部函数():
    ...
    def 内部函数():
        ...
    return 内部函数
'''

例子

#例子
def func(a,b):
    c=10

    def inner_func():
        s=a+b+c
        print('相加之后的结果是:',s)
    return inner_func

#调用func
ifunc=func(6,9)
ifunc1=func(2,8)
#调用反出来的内部函数
ifunc1()
ifunc()
'''
相加之后的结果是: 20
相加之后的结果是: 25
'''

同级闭包

#同级闭包
'''
闭包有什么缺点?
1.作用域没有那么直观
2.因为变量不会呗垃圾回收所以有一定的内存占用问题

作用:
1.可以使用同级的作用域!!
2.读取其他元素的内部变量
3.延长作用域

总结:
1.闭包优化了变量,原来需要类对象完成的工作,闭包也可以完成
2.由于闭包引用了外部函数的局部变量,则外部函数的局部变量没有及时释放,消耗内存
3.闭包的好处,使代码变得更简洁,便于阅读代码
4.闭包是理解装饰器得基础

'''
def func():
    a=100

    def inner_func1():
        b=90
        s=a+b
        print(s)
    def inner_func2():
        inner_func1()
        print('---inner_func2')
    return inner_func2

x=func()
x()
'''
190
---inner_func2
'''

装饰器引入

#闭包回顾(返回函数的地址出来)
def func(number):
    a=100
    def inner_func():
        nonlocal a
        nonlocal number
        number+=1
        for i in range(number):#对a进行number+1次加1
            a+=1
        print('修改后的a:',a)
    return inner_func

#调用func
f=func(5)
f()#修改后的a: 106



#地址引用变量和函数
a=10
b=a
print(a)#10
print(b)#10

def test():
    print('test-----')

t=test
#调用
t()#test-----
test()#test-----



#函数地址作为参数(装饰器)
def func1(f):
    print(f)
    f()#调用参数中的函数
    print('--->func')
func1(test)#注意test参数不要带括号
'''
<function test at 0x000001886707A048>
test-----
--->func
'''

装饰器使用

def house():
    print('我是毛胚房')


def house1():
    house()
    print('刷漆')
    print('铺地板')
#调用函数
house1()
'''
我是毛胚房
刷漆
铺地板
'''


'''
装饰器特点:
1.函数A是作为参数出现的(函数B接收函数A作为参数)
2.要有闭包的特点(外部函数调用外部函数的变量&外部函数返回内部函数的地址)
'''
#定义一个装饰器
def decoratea(func):
    a=100

    def wrapper():
        func()
        print('----->刷漆')
        print('---->铺地板',a)
        print('---->装门')
    return wrapper

#使用装饰器
@decoratea#表示把下面的函数作为参数传给这个装饰器
def house():
    print('我是毛胚房')
#调用函数house
print(house)
house()#本质是调用wrapper,wrapper里面调用真实house

'''
<function decoratea.<locals>.wrapper at 0x000001CEB9969158>
我是毛胚房
----->刷漆
---->铺地板 100
---->装门
'''
'''
@装饰器类名底层调用步骤:
1.house作为被装饰函数
2.将被装饰函数作为参数传给装饰器decoratea
3.执行decoratea函数  
3.1 a=100
3.2 加载函数wrapper进入内存,但是没有调用
4.将返回值赋值给被装饰函数house,因此当我们调用house时其实是调用wrapper函数,
  而wrapper函数里面调用了函数参数func才是我们真正的house函数

'''

无参例子

#例子
import time


def decorator2(func):
    def wrapper():
        print('正在校验中...')
        time.sleep(2)
        print('检验完成..')
        #调用原函数
        func()
    return wrapper

@decorator2
def f1():
    print('----f1--')

'''
正在校验中...
检验完成..
----f1--
'''
'''
@decorator2底层:
1.把f1当作被装饰函数
2.调用decorator2
3.把返回值赋值给f1
'''
f1()
#调用返回值wrapper函数,wrapper函数里面调用f1

有参例子

#例子
import time


def decorator2(func):
    def wrapper(x):
        print('正在校验中...')
        time.sleep(2)
        print('检验完成..')
        #调用原函数,原函数有参数,这里也要有
        func(x)
    return wrapper

@decorator2
def f1(n):
    print('----f1--',n)

'''
正在校验中...
检验完成..
----f1-- 5
'''
f1(5)#本质是调用wrapper,因此wrapper也要有参数
#调用返回值wrapper函数,wrapper函数里面调用f1

@decorator2
def f3(students):
    for stu in students:
        print(stu)
students=['lily','tom','lucy']

f3(students)
'''
正在校验中...
检验完成..
lily
tom
lucy
'''

可变参数例子

#如果现在某个被装饰类传入两个参数?
#----》修改装饰类的参数为可变参数

#例子
import time


def decorator2(func):
    def wrapper(*x):  #*x是5,x是(5,)
        print('正在校验中...')
        time.sleep(2)
        print('检验完成..')
        #调用原函数,原函数有参数,这里也要有
        func(*x)  #对元组拆包,*x是5,将5作为参数
    return wrapper

@decorator2
def f1(n):
    print('----f1--',n)

'''
正在校验中...
检验完成..
----f1-- 5
'''
f1(5)#本质是调用wrapper,因此wrapper也要有参数
#调用返回值wrapper函数,wrapper函数里面调用f1

@decorator2
def f2(name,age):
    print('----f2---',name,age)
f2('lily',20)
'''
正在校验中...
检验完成..
----f1-- 5
正在校验中...
检验完成..
----f2--- lily 20
'''

带关键字参数的装饰器

# 带关键字参数的装饰器
import time
def decorate(func):
    def wrapper(*args,**kwargs):
        print('正在校验...')
        time.sleep(2)
        print('校验完毕...')
        #调用原函数
        func(*args,**kwargs)
    return wrapper

@decorate
def f3(students, clazz='1905'):
    print('{}班级的学生如下:'.format(clazz))
    for stu in students:
        print(stu)


students = ['lily', 'tom', 'lucy']
f3(students, clazz='1904')
'''
正在校验...
校验完毕...
1904班级的学生如下:
lily
tom
lucy
'''



双层装饰器

#双层装饰器
def zhuang1(func):
    print('--->1 start')

    def wrapper1(*args,**kwargs):
        func()
        print('刷漆')
    print('--->1 end')
    return wrapper1

def zhuang2(func):
    print('--->2 start')
    def wrapper2(*args,**kwargs):
        func()
        print('铺地板,装门..')
    print('---->2 end')
    return wrapper2

@zhuang2
@zhuang1
def house():
    print('我是毛胚房...')

#调用
house()
'''
1.@zhuang1底层
2.@zhuang2底层
3.调用house,看当前house本质是谁
双层装饰器的调用是符合就近原则,先调用zhuang1,把house作为zhuang1的参数,zhuang1返回wrapper1给house,此时house=wrapper1
然后zhuang2就把house(此时是wrapper1)作为参数,返回wrapper2给house,此时house=wrapper2
接着调用了house,实际是调用wrapper2,里面的func是wrapper1,wrapper里面的func是原始的house
'''
'''
--->1 start
--->1 end
--->2 start
---->2 end
我是毛胚房...
刷漆
铺地板,装门..
'''

装饰器带参数

#装饰器带参数(必须用三层函数才可以使得装饰器带参数)
'''
带参数的装饰器是三层的
最外层的函数负责接收装饰器参数
里面的内容还是原装饰器的内容

'''
def outer(a):#在原来两层基础上多加一层用来接收参数
    def decorate(func):
        def wrapper(*args,**kwargs):
            func(*args)
            print('---->铺地砖{}块'.format(a))
        return wrapper
    return decorate

@outer(10)
def house(time):
    print('我{}日期拿到的房子的钥匙,是毛胚房..'.format(time))

house('2021-05-08')
'''
我2021-05-08日期拿到的房子的钥匙,是毛胚房..
---->铺地砖10'''

@outer(100)
def street():
    print('新修街道名字是:黑泉路')

street()
'''
新修街道名字是:黑泉路
---->铺地砖100'''

装饰器的应用

#装饰器的应用
#开发:登录验证
import time

#登录状态
islogin=False

def login():
    global islogin
    username=input('请输入用户名')
    password=input('请输入密码')
    if username=='admin' and password=='123456':
        islogin=True

#定义一个装饰器,进行付款验证
def login_required(func):
    def wrapper(*args,**kwargs):
        print('---付款----')
        #验证用户有没有登录
        if islogin:
            func(*args,**kwargs)
        else:
            #跳转到登录页面
            print('请先进行登录')
            login()
    return wrapper

@login_required
def pay(money):
    print('正在付款,付款金额是{}元'.format(money))
    print('付款中...')
    time.sleep(1)
    print('付款完成')

#调用
pay(100)
pay(200)

'''
---付款----
请先进行登录
请输入用户名admin
请输入密码123456
---付款----
正在付款,付款金额是200元
付款中...
付款完成
'''
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值