装饰器函数:
开放&封闭
在编程领域,有这么两个原则是必须遵守的,具体就是开放封闭的原则,具体如下:
封闭:已实现的功能代码不应该被修改
开放:对现有功能的扩展开放
如果我们有N个函数,我们需要在N个函数中增加或者减少⼀个功能,那么也就意味着我们需要把同样的代码增加多次或者是减少多次,很明显这不符合开放封闭的原则,⽽且也不是⼀个好的编程⻛格,那么解决思路是什么了?
解决思路就是装饰器。我们来写⼀个简单的装饰器,再来看它的调⽤顺序和过程,具体代码如下:
def outer(func):
def inner():
print('this is a log info')
func() #相当于执行fun()函数
return inner
@outer
def fun():
print('this is a function fun')
if __name__ == '__main__':
fun()
输出结果:
this is a log info
this is a function fun
先执⾏outer的函数
再执⾏内部函数inner
下来执⾏到inner函数的返回值
再具体到inner的函数,执⾏inner函数⾥⾯的表达式对于被装饰的函数⽽⾔,⼀般是有返回值的信息,那么意味着我们的装饰函数也需要做下调整,调整后的代码如下:
def outer(funObect):
def inner():
print('this is a log info')
return funObect()
return inner
@outer
def func():
return 'this is a function'
if __name__ == '__main__':
print(func())
装饰器参数
凡事函数,⼤多数的时候,都是有形式参数的,那么我们的装饰器的函数也需要考虑和兼容这种情况,就像我们之前在动态参数⾥⾯讲的⼀样,⼀个函数的形式参数可能会有多个,也可能是不同的数据类型,⽐如列表,元组,和字典的数据类型,调整后的代码如下:
def outer(funObect):
def inner(*args,**kwargs):
print('hello,python')
return funObect(*args,**kwargs) #引用装饰器的函数带有参数
return inner
@outer
def login(username,password):
if username=='wuya' and password=='admin':
return '登录成功!'
else:
return False
if __name__ == '__main__':
print(login(username='wuya',password='admin'))
装饰器函数实战 :
访问后台管理系统:思路:主函数循环执行1-5,输入1就调用注册函数,注册成功后把用户名密码保存到文件中,登录时读取保存的用户名密码,查看个人主页和后台管理校验用户名和密码是否正确
#未引用装饰器函数之前
USER_LOGIN={'isLogin':False}
def register():
'''注册'''
username=input('请⽤户⽤户名:\n')
password=input('请输⼊密码:\n')
temp=username+'|'+password
with open('login.txt','w') as f:
f.write(temp)
def login():
'''登录'''
username=input('请⽤户⽤户名:\n')
password=input('请输⼊密码:\n')
lists=None
with open('login.txt') as f:
lists=f.read() #Python常⽤库与IO操作
lists=lists.split('|')
if username==lists[0] and password==lists[1]:
USER_LOGIN['isLogin']=True
USER_LOGIN['nick']='wuya'
print(USER_LOGIN)
else:
print('请输⼊正确的账户和密码')
def profile():
'''个⼈主⻚'''
if USER_LOGIN['isLogin']:
print('欢迎{0}访问个⼈主⻚的信息!'.format(USER_LOGIN['nick']))
else:
print('请登录')
def admin():
'''后台系统'''
if USER_LOGIN['isLogin']:
print('欢迎访问后台管理系统的信息')
else:
print('请登录')
def main():
'''执⾏的主函数'''
while True:
try:
f=int(input('1、注册 2、登录 3、个⼈主⻚ 4、后台系统 5、退出\n'))
if f==1:
register()
elif f==2:
login()
elif f==3:
profile()
elif f==4:
admin()
elif f==5:
break
except :continue
if __name__ == '__main__':
main()
-------------------------------------------------------------------------
#引用装饰器函数之后
userLogin = {'isLogin':False}
def outer(func):
def inner(*args,**kwargs):
if userLogin['isLogin']:
return func() #执行引用装饰器的函数
else:
print("请登录")
return inner
#重复的代码提取出来
def info():
username = input("请输入用户名\n")
password = input("请输入密码\n")
return username,password
#注册
def register():
username,password = info()
temp = username+ "|" +password
with open('venv/login.txt', 'w') as f:
f.write(temp)
# 登录
def Login():
username,password = info()
list = None
with open('venv/login.txt', 'r') as f:
list = f.read()
lists = list.split("|")
if username ==lists[0] and password ==lists[1]:
userLogin['isLogin'] = True
userLogin['nick'] = 'xcj'
print(userLogin)
print("{0}登录成功".format(userLogin['nick']))
else:
print("请输入正确的用户名密码")
#个人主页
@outer
def profile():
print("欢迎{0}进入个人主页".format(userLogin['nick']))
#后台管理
@outer
def admin():
print("欢迎{0}进入后台管理".format(userLogin['nick']))
def main():
while True:
try:
f = int(input('1、注册 2、登录 3、个人主页 4、后台管理 5、退出\n'))
if f ==1:
register()
elif f ==2:
Login()
elif f ==3:
profile()
elif f ==4:
admin()
elif f ==5:
break
except:continue
if __name__ == '__main__':
main()
生成器实战:
列表推导式:
需求:列表里的每个对象+1
list1 = [1, 2, 3, 4, 5, 6]
# 常规写法
def list_add():
result = []
for i in list1:
result.append(i + 1)
return result
# 列表推导式
print([item + 1 for item in list1])
这种简单的⽅式我们使⽤专业的话来说,把它叫:列表推导式。
for右边的代码是对⼀个值进⾏循环输出,左边的 是对输出的每个对象进⾏+1,
也就是表达式,最后整体输出结果信息
生成器:
在⼀个列表中我们可以使⽤推导式的⽅式存储很多的对象,但是⽐如100万了,这样内存资源是⽆法解决的,特别是在gRPC的stream通信交互中,使⽤之前的⽅式是⽆法解决的。是否存在循环的⼀边进⾏计算的⽅式的,这样的机制我们叫⽣成器,也就是generator。如下代码演示这部分,具体如下:
g = (item + 1 for item in list1)
# 而g是一个generator
print(g)
列表推导式的 [] 换成()就创建了一个生成器对象
如果想拿到generator⾥⾯的内容,可以使⽤next(generator的对象)。具体如下:
g=(x for x in range(3))
if __name__ == '__main__':
print(next(g))
print(next(g))
print(next(g))
print(next(g))
输出结果:
0
1
2
Traceback (most recent call last):
File "/Applications/code/Yun/Issue9/Python函数/demo.py", line 10, in <module>
print(next(g))
StopIteration
遇到StopIteration的错误是合理的,因为每次调⽤next(g)它会输出下⼀个元素的值,但是generator⾥⾯的值它是有限的,直到最后⼀个元素的值,再往后输出就会报StopIteration的错误信息了。使⽤next(g)这样的⽅式⽐较低效,凡事generator它都是可以被循环的,
修改上⾯的代码如下:
g=(x for x in range(3))
if __name__ == '__main__':
for item in g:
print(item)
⼀般来说,创建了generator后,都会通过for来循环输出它⾥⾯的对象的,很少使 ⽤next()的。
⼀般性的针对⼀个generator的循环输出,我们可以使⽤yield的关键字,如下案例所示:
def func(list1):
for item in list1:
yield item
if __name__ == '__main__':
for item in func(list1=[x for x in range(3)]):
print(item)
迭代器实战:
在前⾯的学习基础上,直接可⽤于for循环的具体主要为:
list
tuple
dict
set
等
这些能够被for循环的对象称为可迭代的对象,也就是Interable。可以使⽤isinstance来判断⼀个是不是Interable,具体如下:
from collections.abc import Iterable
print(isinstance([], Iterable))
print(isinstance((), Iterable))
print(isinstance("abc", Iterable))
print(isinstance([x for x in range(10)], Iterable))
print(isinstance({'name': 'wuya', 'age': 18}, Iterable))
⽣成器与迭代器的区别是:
⽣成器也是可以被for来进⾏循环的,也还可以被next()函数不断调⽤并返回下⼀个值的信息,直到最后出现StopIteration的错误信息
迭代器可以被next()函数调⽤并不断返回下⼀个值的对象
在Python中,Iterable对象表示的是⼀个数据流,Iterable对象可以被next()函数调⽤并不断返回下⼀个数据。所以 Iterable主要应⽤于流式的数据,如:
list1 = [
{'name': 'wuya', 'age': 18, 'address': 'xian'},
{'name': 'wuya2', 'age': 19, 'address': 'xian'},
{'name': 'wuy3', 'age': 20, 'address': 'xian'},
{'name': 'wuya4', 'age': 21, 'address': 'xian'},
{'name': 'wuya5', 'age': 22, 'address': 'xian'},
{'name': 'wuya6', 'age': 23, 'address': 'xian'},
{'name': 'wuya7', 'age': 24, 'address': 'xian'},
{'name': 'wuya8', 'age': 25, 'address': 'xian'}
]
def func():
for item in list1:
yield item
if __name__ == '__main__':
print('函数func的类型:', type(func())) #函数func的类型: <class 'generator'>
for item in func():
print(item)