发布时间:2018-04-03 20:35:01编辑:Run阅读(3970)
开放封闭原则
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--迭代器,生成器
48327
47137
38004
35298
29793
26477
25415
20416
20103
18551
127°
129°
119°
191°
159°
399°
220°
214°
257°
448°