原来这就是装饰器啊

1. 编写函数(函数的执行时间是随机的)

import random, time       # 导入模块


def random_time():        # 定义random_time函数
    print('Start')
    time.sleep(random.randint(1, 5))     # 实现随机执行时间
    print('End')


random_time()          # 调用random_time函数

2. 编写装饰器,为函数加上统计时间的功能

from functools import wraps          # 导入模块
import time, random


def timmer(func):                 # 定义装饰器函数
    @wraps(func)                  # 为装饰器加上一个装饰器,使咱们写的装饰器更完美
    def wrapper(*args, **kwargs): 
        start_time = time.time()
        res = func(*args, **kwargs)
        stop_time = time.time()
        print('Run time is %s' % (stop_time - start_time))
        return res                # 将原函数返回值返回

    return wrapper                # 将wrapper函数地址返回


@timmer                           # 调用timmer装饰器
def random_time():
    print('Start')
    time.sleep(random.randint(1, 5))
    print('End')


random_time()                     # 调用random_time函数(实则是调用的wrapper函数。)

3. 编写装饰器,为函数加上认证的功能

from functools import wraps
def auth(func):               # 定义装饰器
    @wraps(func)                  # 使装饰器更完美
    def wrapper(*args, **kwargs):
        inp_name = input('Username  >>:').strip()
        inp_pwd = input('Password  >>:').strip()
        if inp_name == 'Catalog Spri' and inp_pwd == '123':   # 认证成功
            res = func(*args, **kwargs)
            return res
        else:               # 认证失败
            print('Username or password error.')

    return wrapper


@auth
def home(name):
    print('Hello %s, welcome' % name)


home('Catalog Spri')         # 调用home函数(实则调用的wrapper函数)

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

注意:从文件中读出来的字符串形式的字典,可以用eval('{'name' : 'egon', 'password' : '123'}')转成字典格式

from functools import wraps              # 从functools库导入wraps功能

auth_status = {'name': None}             # 定义登录状态


def auth(func):                         # 定义装饰器
    @wraps(func)                        # 使装饰器更完美
    def wrapper(*args, **kwargs):
        if auth_status['name'] is not None:      # 判断登录状态
            res = func(*args, **kwargs)
            return res
        inp_name = input('Username  >>:').strip()
        inp_pwd = input('Password  >>:').strip()
        with open('account.txt') as f:
            for line in f:
                info = eval(line.strip('\n'))  # eval可以将字典、列表、元组等与字符串进行转换
                if info['name'] == inp_name and info['password'] == inp_pwd:
                    auth_status['name'] = inp_name      # 记录登录状态
                    res = func(*args, **kwargs)         # 认证成功
                    return res
            else:                   # 认证失败
                print('Username or password error.')

    return wrapper


@auth
def home(name):
    print('Hello %s, welcome.' % name)


@auth
def index():
    print('Welcome to the index page')


index()                          # 这里的函数的调用实则都是在调用wrapper函数。
home(auth_status['name'])

5. 编写装饰器,为多个函数加上认证功能,要求登陆成功一次,在超时时间内无需重复登录,超过了超时时间,则必须重新登录

from functools import wraps
import time           # 导入模块

auth_status = {'name': None}       # 记录登录状态


def auth(func):             # 定义装饰器
    @wraps(func)            # 使装饰器变得完美
    def wrapper(*args, **kwargs):
        if auth_status['name'] is not None:      # 判断登录状态
            res = func(*args, **kwargs)
            return res
        inp_name = input('Username  >>:').strip()
        inp_pwd = input('Password  >>:').strip()
        if inp_name == 'egon' and inp_pwd == '123':     # 认证成功
            auth_status['name'] = inp_name         # 记录登录状态
            res = func(*args, **kwargs)
            return res
        else:                        # 认证失败
            print('Username or password error.')

    return wrapper


@auth
def home():
    print('Welcome to home page')


@auth
def index():
    print('Welcome to the index page')


while True:        # 循环执行
    home()
    index()
    time.sleep(10)         # 10秒钟后清除登录状态,让用户重新登录再进行操作
    auth_status['name'] = None

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

import requests             # 导入requests模块


def get(url):         # 定义函数
    response = requests.get(url)      # 爬取网址url的内容
    if response.status_code == 200:      # 判断状态
        return response.text


url = input('>>:')
print(get(url))

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

扩展功能:用户可以选择缓存介质/缓存引擎,针对不同的url,缓存到不同的文件中

# 这一题实现的并不完美,做到了写入不同文件内,但是看了一眼老师的标准答案,发现自己可能理解有误。
# 扩展功能实现的不够标准。但是还是实现了。各位有什么好的思路可以一起讨论一下
import requests              # 导入模块
from functools import wraps


def download(func):
    @wraps(func)            # 令装饰器变得完美
    def wrapper(*args, **kwargs):
        with open(db, mode='a+', encoding='utf-8') as data: # 按用户输入的文件路径打开文件
            data.seek(0)       # 移动文件指针到开头
            if len(data.read()) > 0:     # 判断文件是否有内容
                data.seek(0)    # 前面read了一次,所以要再次移动文件指针
                res = data.read()    
                return res
            else:          # 文件没内容则执行get函数进行下载
                res = func(*args, **kwargs)
                data.write(res)      # 将爬取的内容按照用户规定路径写入文件中
                return res

    return wrapper


@download
def get(url, db):        # 爬取一个网页的内容
    response = requests.get(url)
    if response.status_code == 200:
        return response.text


url = input('URL  >>:')
db = input('File path  >>:')
get(url, db)

8. 还记得我们用函数对象的概念,制作一个函数字典的操作吗,来来来,我们有更高大上的做法,在文件开头声明一个空字典,然后在每个函数前加上装饰器,完成自动添加到字典的操作

from functools import wraps

functions = {}             # 定义空字典方便将函数放进去


def add(func):
    @wraps(func)       # 一定要记得有这一步,会令装饰器变得完美
    def wrapper(*args, **kwargs):
        for i in functions:     # 循环字典,判断func是否已经存在
            if functions[i] == func:
                break
        else:          # 遍历字典没找到func则将func添加进字典
            functions[str(len(functions))] = func  # 添加时要与数字建立关系
        res = func(*args, **kwargs)
        return res

    return wrapper


@add
def login():
    print('Log in successful')


@add
def shopping():
    print("I'm shopping now")


@add
def pay():
    print("Pay for goods")


@add
def charge():
    print('Charge money')

9. 编写日志装饰器,实现功能:一旦函数f1执行,则将消息2018-09-27 13:30:21  f1 run 写入到日志文件中,日志文件路径可以指定

注意:时间格式的获取

import time

time.strftime('%Y-%m-%d %X')

from functools import wraps   # 导入模块
import time


def log(file_path):     # 需要传入文件路径,所以要再外包一层
    def inner(func):
        @wraps(func)    # 这一步真的很重要!一定要记得
        def wrapper(*args, **kwargs):     
            with open(file_path, mode='a', encoding='utf-8') as f:  # 打开日志文件
                time_now = time.strftime('%Y-%m-%d %X')   # 获取当前时间
                res = func(*args, **kwargs)    # 运行func函数
                f.write('%s | %s | run\n' % (time_now, func.__name__))  # 写入日志
                return res                   # 通过func.__name__可以获取函数名

        return wrapper

    return inner


@log('log.txt')
def f1():
    pass


f1()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Noah Ren

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值