发布时间:2018-04-03 20:35:01编辑:Run阅读(3693)
开放封闭原则
1 对扩展是开放的
为什么要对扩展开放呢?
我们说,任何一个程序,不可能在设计之初就已经想好了所有的功能并且未来不做任何更新和修改,所以我们必须允许代码扩展,添加新功能
2 对修改是封闭的
为什么要对修改封闭呢?
就像我们刚刚提到的,因为我们写的一个函数,很有可能已经交付给其他人使用了,如果这个时候我们对其进行了修改,很有可能影响其他已经在使用该函数的用户
函数的有用信息
def func1(): """ 此函数打印函数名与注释 :return:返回值为True """ print(666) print(func1.__name__) # func1.__name__ 函数名 print(func1.__doc__) # funcl.__doc__ 注释信息 return True func1() print(func1())
执行结果
例2
使用装饰器打印出函数的相关信息
from functools import wraps def deco(f): @wraps(f) # 加在最内层函数正上方 def wrapper(*args, **kwargs): return f(*args, **kwargs) return wrapper @deco # test = deco(test) def test(): '''测试''' print('from test') test() print(test.__name__) # 打印函数名 print(test.__doc__) # 打印注释信息
执行结果
from test
test
测试
带参数的装饰器
import time flag = False #标志位 def timer(flag): def wrapper(f): def inner(*args, **kwargs): if flag: start_time = time.time() ret = f(*args, **kwargs) time.sleep(0.3) end_time = time.time() print("次函数的执行效率{}".format(end_time - start_time)) else: ret = f(*args, **kwargs) return ret return inner return wrapper flag = True @timer(flag) def func1(): print(666) @timer(flag) def func2(): print(777) func1() func2()
执行结果
多个装饰器装饰一个函数
def warpper1(func): def inner1(*args, **kwargs): print("wrapper1, before func") # 2 func(*args, **kwargs) print("wrapper1, after func") # 4 return inner1 def wrapper2(func): def inner2(*args, **kwargs): print('wrapper2, before func') # 1 func(*args, **kwargs) print('wrapper2, after func') # 5 return inner2 @wrapper2 # f = wrapper2(f) 里面的f=inner1 外面的f == inner2 @warpper1 # f = wrapperl(f) 最里面的f==函数名f,外面的f==inner1 def f(): print('in f') # 3 f()
执行结果
练习题
# !/usr/bin/env python # coding: utf-8 __author__ = 'www.py3study.com' 1.写函数,返回一个扑克牌列表,里面有52项,每一项是一个元组 例如:[(‘红心’,2), (‘草花’,2), …(‘黑桃’,‘A’)] list1 = ['黑桃♠', '红心♥', '梅花♣', '方块♦'] list2 = ['A', 2, 3, 4, 5, 6, 7, 8, 9, 10, 'J', 'Q', 'K'] 1 位置传参 def poker(*args, **kwargs): list3 = [] for x in args[0]: for y in args[1]: list3.append((x, y)) return list3 print(poker(list1, list2)) 2 关键字传参 def poker(*args, **kwargs): list4 = [] for x in kwargs['test1']: for y in kwargs['test2']: list4.append((x, y)) return list4 print(poker(test1=list1, test2=list2)) 3 for range def func(li): l = [] for i in li: for j in range(1, 14): l.append((i, j)) return l print(func(['黑桃♠', '红心♥', '梅花♣', '方块♦'])) 2. 写函数,传入n个数,返回字典 {‘max’:最大值,’min’:最小值} 例如: min_max(2, 5, 7, 8, 4) 返回: {‘max’:8,’min’:2} def compare(*args, **kwargs): return {'max': max(args), 'min': min(args)} print(compare(12, 324, 54,1,3,4,10,5,6,7)) 3. 写函数,专门计算图形的面积 其中嵌套函数,计算圆的面积,正方形的面积和长方形的面积 调用函数area(‘圆形’, 圆半径) 返回圆的面积 调用函数area(‘正方形’, 边长) 返回正方形的面积 调用函数area(‘长方形’, 长,宽) 返回长方形的面积 def area(*args, **kwargs): if args[0] == '圆形': def rectangle_area(): s1 = 3.14 * args[1] return s1 return rectangle_area() elif args[0] == '正方形': def square_area(): s2 = args[1] * args[1] return s2 return square_area() else: def circular_area(): s3 = args[1] * args[2] return s3 return circular_area() print(area("圆形", 6)) print(area("正方形", 5)) print(area("长方形", 2, 3)) 4. 写函数,传入一个参数n,返回n的阶乘 例如: cal(7) 计算7 * 6 * 5 * 4 * 3 * 2 * 1 1 递归求解,设置一个出口 def factorial(n): if n == 1: return 1 return n * factorial(n - 1) print(factorial(7)) 2 for range利用*=求解 def func(n): count = 1 for i in range(n,0,-1): count *= i return count print(func(7)) 5、编写下载网页内容的函数,要求功能是:用户传入一个url,函数返回下载页面的结果(升级题) 5.1.为题目3编写装饰器,实现缓存网页内容的功能:(升级题) 具体:实现下载的页面存放于文件中,如果网页有对应的缓存文件,就优先从文件中读取网页内容,否则,就去下载,然后存到文件中 import urllib.request import os import time # def download_index(*args, **kwargs): # for i in args: # url = 'https://' + str(i) # response = urllib.request.urlopen(url).read().decode('utf-8') # with open('download.txt', encoding='utf-8', mode='w') as f2: # f2.write(response) # return response # print(download_index('www.baidu.com')) import urllib.request import os import time def download_index(*args, **kwargs): flag = False def inner(): if os.path.isfile('download.txt') == flag: for i in args: url = 'https://' + str(i) req = urllib.request.Request(url) req.add_header('User-Agent', 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:50.0) Gecko/20100101 Firefox/50.0') response = urllib.request.urlopen(req).read().decode('utf-8') time.sleep(1) with open('download.txt', encoding='utf-8', mode='w') as f2: f2.write(response) return response else: with open('download.txt', encoding='utf-8', mode='r') as f3: print(inner.__closure__) return f3.read() return inner print(download_index('www.baidu.com')()) 6 给每个函数写一个记录日志的功能, 功能要求:每一次调用函数之前,要将函数名称,时间节点记录到log的日志中。 所需模块: import time from functools import wraps def timer(f): @wraps(f) def inner(*args, **kwargs): struct_time = time.localtime() ss = time.strftime("%Y-%m-%d %H:%M:%S", struct_time) with open("log.txt", encoding='utf-8', mode='a') as f1: f1.write("函数名:{}\t函数描述:{}\t运行时间:{}\n".format(f.__name__, f.__doc__, ss)) ret = f(*args, **kwargs) '''函数执行之后''' return ret return inner @timer def test1(): '''this is test1''' print('in test1') @timer def test2(): '''this is test2''' time.sleep(3) print('in test2') test1() test2() 7、编写装饰器,为多个函数加上认证的功能(用户的账号密码来源于文件),要求登录成功一次,后续的函数都无需再输入用户名和密码 方法1 flag = False dic = {} def test(): while True: username = input("输入账户名:").strip() if not username.strip(): print('账号不能为空') else: password = input("输入密码:").strip() if not password.strip(): print('密码不能为空') else: with open('user_pwd', encoding='utf-8', mode='r') as fq: for i in fq: s = i.strip().split() dic[s[0]] = s[1] for i in dic.items(): if username == i[0] and password == i[1]: global flag flag = True break else: flag = False if flag: print("登录成功") return True else: print("账号或密码错误!") def wrapper(f): def inner(*args, **kwargs): if flag: f(*args, **kwargs) return f else: print("请先登录") test() f(*args, **kwargs) return inner @wrapper def test1(): print("this is test1") @wrapper def test2(): print("this is test2") test1() test2() 方法2 dic = { 'username': None, 'status': False, } def wrapper(func): def inner(*args, **kwargs): if dic['status']: ret = func(*args, **kwargs) return ret else: i = 0 while i < 3: username = input("请输入用户名:").strip() password = input("请输入密码:").strip() with open('user_pwd', encoding='utf-8', mode='r') as f: for j in f: j_li = j.strip().split() # ['张三', '123'] if username == j_li[0] and password == j_li[1]: dic['username'] = username dic['status'] = True ret = func(*args, **kwargs) return ret else: print('账号或密码错误,请重新输入{}机会'.format(2 - i)) i += 1 return inner @wrapper def article(): print('欧美专区......') @wrapper def diary(): print('日韩专区......') @wrapper def file(): print('泰国专区......') @wrapper def comment(): print('北美专区......') article() diary() file() comment() 8,在编写装饰器,为多个函数加上认证的功能(用户的账号密码来源于文件),要求登录成功一次,后续的函数都无需再输入用户名和密码。这个作业之上进行升级操作: 设置两套密码,一套为京东账号密码,一套为淘宝账号密码保存在文件中。 设置四个函数,分别代表 京东首页,京东超市,淘宝首页,淘宝超市。 循环打印四个选项:东首页,京东超市,淘宝首页,淘宝超市。 供用户选择,用户输入选项后,执行该函数,四个函数都加上认证功能,只要登陆成功一次,在选择其他函数,后续都无需输入用户名和密码。 相关提示:用带参数的装饰器。装饰器内部加入判断,验证不同的账户密码。 方法1 import time import platform import os class Shopping(object): '''初始化''' def __init__(self, *args, **kwargs): self.timeout = 1 self.flag = False self.sign = False self.jd_dic = {} self.tb_dic = {} self.run = { '0': self.Error, '1': self.jd_home_page, '2': self.jd_supermarket, '3': self.taobao_home_page, '4': self.taobao_supermarket, } self.main() '''装饰器''' def app(func): def inner(self): if self.sign: func(self) return func else: print("|| 请先登录!!!!") self.jd_or_tb() func(self) return inner '''程序入口''' def main(self, *args, **kwargs): while True: self.menu() op = input(u'|| 输入选项:').strip() '''map判断输入是否符合条件''' if op == '0': exit() elif op in map(str, range(len(self.run))): self.run.get(op)() else: self.error() continue def menu(self, *args, **kwargs): self.clear() self.create_text() print(u'=' * 40) print(u'|| 0:退出程序') print(u'|| 1:京东首页') print(u'|| 2:京东超市') print(u'|| 3:淘宝首页') print(u'|| 4:淘宝超市') print(u'=' * 42) def clear(self, *args, **kwargs): OS = platform.system() if (OS == u'Windows'): os.system('cls') else: os.system('clear') '''创建密码文件''' def create_text(self, *args, **kwargs): if os.path.isfile('jd_name_pwd.txt') == self.flag: with open("jd_name_pwd.txt", encoding='utf-8', mode='w') as f: f.write('zhangsan' + ' ' + '123') else: with open('jd_name_pwd.txt', encoding='utf-8', mode='r') as f1: for i in f1: ss = i.strip().split() self.jd_dic['name'] = ss[0] self.jd_dic['pwd'] = ss[1] if os.path.isfile('taobao_name_pwd.txt') == self.flag: with open('taobao_name_pwd.txt', encoding='utf-8', mode='w') as f2: f2.write('lisi' + ' ' + '123') else: with open('taobao_name_pwd.txt', encoding='utf-8', mode='r') as f3: for i in f3: ss = i.strip().split() self.tb_dic['name'] = ss[0] self.tb_dic['pwd'] = ss[1] def jd_or_tb(self,*args, **kwargs): while True: print("|| 1:京东账号:") print("|| 2:淘宝账号:") self.list_jd_or_tb = { '1': self.create_text, '2': self.create_text, } jd_tb = input(u'|| 输入选项:').strip() '''map判断输入是否符合条件''' if jd_tb == '0': return True elif jd_tb in map(str, range(len(self.list_jd_or_tb) + 1)): self.run.get(self.sign_in()) else: self.Error() continue def sign_in(self, *args, **kwargs): while True: username = input('|| 请输入账号:').strip() if not username.strip(): print("|| 账号名不能为空!") else: password = input('|| 请输入密码:').strip() if not password.strip(): print("|| 密码不能为空!") else: if username == self.jd_dic['name'] and password == self.jd_dic['pwd']: print('|| 京东账号登陆成功') self.sign = True self.main() elif username == self.tb_dic['name'] and password == self.tb_dic['pwd']: print('|| 淘宝账号登陆成功') self.sign = True self.main() else: print('账号名或密码错误') @app def jd_home_page(self, *args, **kwargs): print(u'|| 京东-----首页') @app def jd_supermarket(self, *args, **kwargs): print(u'|| 京东-----超市') @app def taobao_home_page(self, *args, **kwargs): print(u'|| 淘宝-----首页') @app def taobao_supermarket(self, *args, **kwargs): print(u'|| 淘宝-----超市') def Error(self, *args, **kwargs): print(u'|| 只能输入1-2的整数,等待{}秒后重新输入'.format(self.timeout)) time.sleep(self.timeout) def error(self, *args, **kwargs): print(u'|| 只能输入1-4的整数,等待{}秒后重新输入'.format(self.timeout)) time.sleep(self.timeout) if __name__ == '__main__': Shopping() 方法2 dic = { 'username': None, 'status': False, } def login(flag): def wrapper(func): def inner(*args, **kwargs): if dic['status']: ret = func(*args, **kwargs) return ret else: i = 0 while i < 3: username = input('请输入用户名:').strip() password = input('请输入密码:').strip() with open('jd_tb', encoding='utf-8') as f: # {'微信': {'username': 'zhangsan', 'password': '123'}, 'qq': {'username': 'lisi', 'password': '123'}, } msg_dic = eval(f.readline()) if username == msg_dic[flag]['username'] and password == msg_dic[flag]['password']: dic['username'] = username dic['status'] = True ret = func(*args, **kwargs) return ret else: print("账号或密码错误,重新输入,还有{}次机会".format(2 - i)) i += 1 return inner return wrapper @login('微信') def taobao_home(): print('淘宝首页') @login('微信') def taobao_shop(): print('淘宝超市') @login('qq') def jingdong_home(): print('京东首页') @login('qq') def jingdong_shop(): print('京东超市') choice_dict = { 1: taobao_home, 2: taobao_shop, 3: jingdong_home, 4: jingdong_shop, } while True: print('1 淘宝首页\n2 淘宝超市\n3 京东首页\n4 京东超市') choice_num = input('选择输入的序号:').strip() if choice_num.isdigit(): choice_num = int(choice_num) if 0 < choice_num <= len(choice_dict): choice_dict[choice_num]() else: print('请输入范围内的序号') else: print('你输入的有非法字符,请重新输入!')
上一篇: python3--函数名本质,函数嵌套,闭包,装饰器
下一篇: python3--迭代器,生成器
47605
45985
36909
34469
29080
25713
24566
19714
19245
17756
5565°
6155°
5691°
5737°
6705°
5483°
5484°
5988°
5965°
7295°