day19 装饰器

Python之路,Day7 = Python基础7


random
wrapper 包装材料;包装纸;书皮
global a 全局的(也就是,函数最外面的那个)
nonlocal a 局部的,上层的函数的变量,如果函数中没有,不会去全局变量中找,直接报错


# 闭包函数: 1.内部函数 2.对外部作用域的引用(全局变量除外)
# 闭包函数的特点:
  自带作用域
  延迟计算或惰性计算
f.__closure__ 所有的闭包函数都有这个方法,也就是说,如果有这个方法,就证明它是闭包函数
f.__closure__[0].cell_contents 查看闭包函数里面的外部包含的变量(只包含自己调用的那个变量)


装饰器
  定义:装饰器本质为任意可调用的对象,被装饰的对象也可以为任意可调用的对象。。。
  功能:在不修改被装饰对象的源代码及调用方式的前提下,为其添加新功能
  原则:
    1.不修改源代码
    2.不修改调用方法

  语法:
    在被装饰的函数上方的一行协商 @装饰器的名字



def outer(func):
  def inner(*args, **kwargs):
    print("111")
    res = func(*args, **kwargs)
    print('222')
    return res
  return inner

======================homework=============

一:编写函数,(函数执行的时间是随机的)
二:编写装饰器,为函数加上统计时间的功能
三:编写装饰器,为函数加上认证的功能

四:编写装饰器,为多个函数加上认证的功能(用户的账号密码来源于文件),要求登录成功一次,后续的函数都无需再输入用户名和密码
注意:从文件中读出字符串形式的字典,可以用eval('{"name":"egon","password":"123"}')转成字典格式

 1 #! /usr/bin/env python
 2 # -*- coding: utf-8 -*-
 3 # __author__ = "Always"
 4 # Date: 2017/6/14
 5 
 6 import time, random
 7 
 8 auth = {'login':False}
 9 
10 def aut():
11     """
12     从文件读取用户名和密码,从而验证是否登录成功
13     登陆成功后,修改登陆状态
14     """
15     while True:
16         username = input('username:').strip()
17         password = input('password:').strip()
18         if not username or not password:continue
19 
20         with open('username', 'r', encoding='utf-8') as f:
21             for i in f:
22                 userinfo = eval(i.strip())
23                 if username == userinfo['name'] and password == userinfo['password']:
24                     auth['login'] = True
25                     return 1
26             else:
27                 print('Inout Error...')
28 
29 
30 def check(func):
31     """
32     检查 auth 的登陆状态,如果为 False, 需要验证,否则,不需要验证
33     :return:
34     """
35     def wrapper(*args, **kwargs):
36         if auth['login'] == False:
37             aut()
38         func()
39     return wrapper
40 
41 def timmer(func):
42     """
43     这个是装饰器
44     为函数添加一个新功能:打印运行程序时使用花费的时间
45     :return:
46     """
47     def wrapper(*args, **kwargs):
48         start_time = time.time()
49         res = func(*args, **kwargs)
50         stop_time = time.time()
51         print('All cost %s.'%(stop_time - start_time))
52         return res
53 
54     return wrapper
55 @check
56 @timmer
57 def say_hello():
58     """
59     打印一个 hello。。。 ,每个字母间隔随机秒
60     :return:
61     """
62     for i in 'Hello。。。':
63         print(i)
64         time.sleep(random.randrange(1,2))
65 
66 @check
67 @timmer
68 def say_goodbye():
69     for i in 'goodbye。。。':
70         print(i)
71         time.sleep(random.randrange(1, 2))
72 
73 # say_hello()
74 
75 say_hello()
76 say_goodbye()

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

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

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

#! /usr/bin/env python
# -*- coding: utf-8 -*-
# __author__ = "Always"
# Date: 2017/6/14

import os, sys, time
if not os.path.exists(r'缓存'):
    os.mkdir(r'缓存')


url_dict = {'baidu':'http://www.baidu.com',
            '52pojie':'http://www.52pojie.cn',
            }


from urllib.request import urlopen


def wrapper(func):
    """
    这是个装饰器,主要的作用是接收一个url的路径,然后返回这个网页的代码
    :param func:
    :return:
    """
    def inner(*args, **kwargs):

        file_name = args[0].split('.')[1]
        if os.path.exists(r'缓存/%s'%file_name) and os.path.getsize(r'缓存/%s'%file_name) > 0:
            with open(r'缓存/%s'%file_name, 'rb') as f:
                print('缓存已经存在,正在读取。。。')
                time.sleep(2)
                return f.read()

        # 将新网址加入字典中
        url_dict[file_name] = args[0]


        print('正在从网上下载。。。')
        time.sleep(2)
        res = func(*args, **kwargs)
        # print(res)
        # print(type(res))

        # print(res)
        # input()
        with open(r'缓存/%s' % file_name, 'wb') as f:
            f.write(res)
        # input('回车键结束。。。。')
        return res
    return inner


@wrapper
def get(url):
    return urlopen(url).read()



# res = get('http://www.baidu.com')
# print(res.decode())

# print(get('http://www.baidu.com').decode())

while True:
    choose_list = []
    for c, i in enumerate(url_dict):
        choose_list.append(i)
        print(' %s  %s		%s'%(c+1, i, url_dict[i]))
    choose = input('
请输入序号或直接输入网址:http://www.baidu.com
>>>').strip()
    if choose.upper() == "Q":
        break
    elif choose.isdigit() and 0 < int(choose) <= len(choose_list):


        res = get(url_dict[choose_list[int(choose) - 1]])
        print(res)
    elif 'http://' in choose:
        res = get(choose)
        print(res)
    else:
        print('输入错误')
    time.sleep(2)

初写代码,BUG,不足之处自然很多,如有问题,欢迎指出。

 谢谢!!!

原文地址:https://www.cnblogs.com/alwaysInMe/p/7011328.html