• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
Fantac
博客园    首页    新随笔    联系   管理    订阅  订阅

Python学习日记(九) 装饰器函数

1.import time

  a.time.time()

  获取到当前的时间,返回值为浮点型

import time
print(time.time())  #1565422783.6497557

  b.time.sleep()

  让程序执行到这个位置暂停一会

import time
start = time.time()
time.sleep(0.5)
print('hello world!')
end = time.time()
print(end - start)  #0.5000286102294922

 

2.装饰器函数

开发原则:开放封闭原则

装饰器的作用:在不改变原函数的情况下,在函数的前后添加功能

装饰器的本质:闭包函数

 

当想要知道一个程序执行的时间

import time
start = time.time()
time.sleep(0.5)
print('hello world!')
end = time.time()
print(end - start)  #0.5000286102294922

再将里面的功能单独拉出来变成一个函数

import time
def func():
    time.sleep(0.5)
    print('hello world!')
def timer(func):
    start = time.time()
    func()
    end = time.time()
    print(end - start)
timer(func)     #hello world!
                #0.5000286102294922

将timer变成一个简单的装饰器

import time
def func():                 #被装饰的函数
    time.sleep(0.5)
    print('hello world!')
def timer(func):            #装饰函数
    def inner():
        start = time.time()
        func()
        end = time.time()
        print(end - start)
    return inner            #回传inner函数的内存地址
get_inner = timer(func)     #后者得到的是inner的内存地址再赋值给get_inner
get_inner()                 #hello world!
                            #0.5000286102294922

执行步骤:

开放封闭原则:开放指的是对扩展开放,封闭指的是对修改封闭

语法糖:@装饰器函数名  可以替代下面的写法

装饰带一般参数且有返回值函数的装饰器

import time
def wrapper(f):     #装饰器函数
    def inner(x):
        res = f(x)
        return res
    return inner
@wrapper            #相当于 fuc = wrapper(fuc)
def fuc(var):       #被装饰的函数
    print(var,'Python')
    return False
res = fuc('Hello')
print(res)

装饰带万能参数的函数装饰器

import time
def wrapper(f):             #装饰器函数
    def inner(*args,**kwargs):
        start = time.time()
        ret = f(*args,**kwargs)
        end = time.time()
        print(end - start)
        return ret
    return inner
@wrapper        #相当于 fuc = wrapper(fuc)
def fuc(a,b,c,d,e = 5):     #被装饰的函数
    time.sleep(0.5)
    print(a,b,c,d,e)
    return e
print(fuc(1,2,3,4,'Python'))

总结:装饰器的模板

import time
def wrapper(f):
    def inner(*args,**kwargs):
        #在被装饰函数之前要做的事
        res = f(*args,**kwargs)
        #在被装饰函数之后要做的事
        return res
    return inner
@wrapper
# func = wrapper(func)
def func():            #被装饰的函数
    return
ret = func()
print(ret)

查看函数信息的方法

def fuc(var):
    '0123456789'
    print(var,'Python')
    return False
print(fuc.__name__) #fuc        主要用于查看函数名
print(fuc.__doc__)  #0123456789    主要用于查看函数的注释

我们在使用fuc()函数的时候实际上我们调用的是inner()函数,如果我们要在不修改原函数的前提下拿到原函数的信息,只需要将inner()函数变成一个装饰器:

def wrapper(f):
    def inner(*args,**kwargs):
        ret = f(*args,**kwargs)
        return ret
    return inner
@wrapper
def fuc():
    print('Python')
    return True
print(fuc())
print(fuc.__name__)     #inner 这里调用的是inner函数

修改后:

from functools import wraps
def wrapper(f):
    @wraps(f)
    def inner(*args,**kwargs):
        ret = f(*args,**kwargs)
        return ret
    return inner
@wrapper
def fuc():
    print('Python')
    return True
print(fuc())
print(fuc.__name__)     #fuc 这里就改回调用的函数名是fuc

 带参数的装饰器

如果许多函数都使用了同一个装饰器,那么它将需要一个布尔值作为参数来作为开关控制它们的使用

FLAGE = False
def wrapper_ctrl(flag):
    def wrapper(fuc):
        def inner(*args,**kwargs):
            if flag:
                print('装饰器已开启...')
                ret = fuc()
                return ret
            else:
                print('装饰器已关闭...')
        return inner
    return wrapper

@wrapper_ctrl(FLAGE)
def function1():
    print('aaaaaaa')

@wrapper_ctrl(FLAGE)
def function2():
    print('bbbbbbb')

@wrapper_ctrl(FLAGE)
def function3():
    print('ccccccc')

function1()     #装饰器已关闭...
function2()     #装饰器已关闭...
function3()     #装饰器已关闭...

多个装饰器装饰一个函数

def wrapper1(fuc):  #2Step:fuc->f
    def inner1(*args,**kwargs):
        print('wrapper1在装饰该函数前要做的事...')     #12Step:print
        fuc(*args,**kwargs)    #13Step:这里的fuc就是f 因为第二步已经传进来了
        print('wrapper1在装饰该函数后要做的事...')     #15Step:print
    return inner1   #3Step:传回inner1

def wrapper2(fuc):  #6Step:fuc->inner1
    def inner2(*args,**kwargs):
        print('wrapper2在装饰该函数前要做的事...')     #10Step:print
        fuc(*args,**kwargs)     #11Step:这里的fuc()实际上是inner1()
        print('wrapper2在装饰该函数后要做的事...')     #16Step:print
    return inner2   #7Step:返回inner2
@wrapper2   #5Step:f = wrapper2(f) 这里的f是inner1 即 f = wrapper2(inner1)
            #8Step:f = inner2
@wrapper1   #1Step:f = wrapper1(f)
            #4Step:f = inner1
#装饰器会找离它最近的函数 离这个函数最近的装饰器会先执行
def f():
    print('abcdefg')        #14Step:print
f() #9Step:这里调用的f()实际上是inner2()

'''执行结果'''
# wrapper2在装饰该函数前要做的事...
# wrapper1在装饰该函数前要做的事...
# abcdefg
# wrapper1在装饰该函数后要做的事...
# wrapper2在装饰该函数后要做的事...

流程图:

 

 

3.和装饰器相关的案例

a.编写装饰器,为多个函数加上认证的功能(用户的账号密码来源于文件),要求登录成功一次,后续的函数都无需输入用户名和密码

FLAG = False        
def login(f):
    def inner(*args,**kwargs):
        global FLAG     
        if FLAG:    #如果已经登入成功
            f(*args,**kwargs)
        else:
            username = input('请输入用户名:')
            password = input('请输入密码:')
            if username.strip() == 'JANE' and password.strip() == '123456':
                FLAG = True
                print('登入成功!')
                f(*args,**kwargs)
            else:
                print('登入失败!')
    return inner
  
get_name('JANE')
get_ID()

b.编写装饰器,为多个函数加上记录调用功能,要求每次调用函数都将把被调用的函数写入文件

def log(f):
    def inner(*args,**kwargs):
        with open('log.txt',mode = 'a',encoding='utf-8') as fileStream:
            fileStream.write(f.__name__ + '\n')
        f(*args,**kwargs)
    return inner
@log
def get_name():
    print('Your username is JANE')
@log
def get_ID():
    print('Your user ID is 110123')
get_ID()
get_name()
get_ID()

c.编写下载网页的函数,要求功能是:用户传入一个url,函数返回下载页面的结果

from urllib.request import urlopen
def get(url):
    html = urlopen(url).read()
    return html
ret = get('http://www.baidu.com')
print(ret)
#<bound method HTTPResponse.read of <http.client.HTTPResponse object at 0x00000000073BC860>>

d.为c编写装饰器,实现缓存网页内容的功能,主要功能:实现下载的页面存放于文件中,如果文件内有值(文件大小不为0),就优先从文件中读取网页内容,否则就去下载,然后存到文件中

import os
from urllib.request import urlopen
def cache(func):
    def inner(*args,**kwargs):
        if os.path.getsize('web_cache'):    #如果不为0 就是True 从文件中找到源码
            with open('web_cache','rb') as f:
                return f.read()
        ret = func(*args,**kwargs)           #取得网页的源码
        with open('web_cache','wb') as f:
            f.write(b'*******' + ret)       #若文件没有网页源码则写入新标志和源码
        return ret
    return inner
@cache
def get(url):
    code = urlopen(url).read()
    return code
end = get('http://www.baidu.com')
print(end)
end = get('http://www.baidu.com')
print(end)
end = get('http://www.baidu.com')
print(end)

 

posted @ 2019-08-10 17:15  Fantac  阅读(405)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3