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\t\t%s'%(c+1, i, url_dict[i])) choose = input('\n请输入序号或直接输入网址:http://www.baidu.com\n>>>').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,不足之处自然很多,如有问题,欢迎指出。
谢谢!!!