python函数式编程-装饰器、生成器、迭代器

装饰器函数:

开放&封闭

在编程领域,有这么两个原则是必须遵守的,具体就是开放封闭的原则,具体如下:
        封闭:已实现的功能代码不应该被修改
        开放:对现有功能的扩展开放
如果我们有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)

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

菜鸟学识

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值