闭包函数 装饰器

闭包函数

     什么叫做函数的闭包 闭包其实就是函数的嵌套 定义在函数的内部 且内部函数用了外部函数名称空间作为名字  从而达到闭包 (函数在定义阶段的时候 他的名称空间查找顺序就已经固定的 不会因为 你的调用位置的改变而改变)

以上就是一个闭包函数 他是先定义 outer函数 然后 a=outer()  因为这里的outer加了()号 所以 他就直接执行了函数outer 同样 它里面的函数不调用是不会执行的 最后一个返回值 inner 这个返回值他会直接给a 因为赋值了 当a加()的时候等价于 inner() 因为a的地址现在指向inner 最后执行print(name) 因为本层没有 就去上层找 发现有就执行了.

闭包还可以这样传参   

 

装饰器  

引入问题: 定义了一个函数,想在运行时动态的增加功能,又不想改动函数本身的代码?

装饰器其实就是一个工具 可以给其他函数添加功能 但是必须要 不能改变原函数的代码 且 不能改变函数的调用方式  开发封闭原则 对扩展开发 对修改关闭.

如何定义一个装饰器?装饰器分为两种  第一是有参装饰器  有参就是func内可以传入参数

                    第二是无参装饰器 就是func内不可传入参数

"""假如说我们想对下面的函数添加功能但是又不能改变他的代码 和调用方式怎么办呢"""
def login():
    print('登录成功')

我们可以使用闭包来写

def outer(func): #这里的func我们来传login的调用方式
    def inner(*args,**kwargs):
         #这里就可以来写他的 添加功能了 假如我们来写一个登录功能
          user_name=input('请登录:').strip()
          if user_name != '':
                res=func(*args,**kwargs)
         return res
return inner login=outer(login) 这里的login不是函数名 指向的地址是inner login()

这样的一个装饰器我们就写好了   
运行流程: 加载 login函数 加载 def outer函数
            运行outer(login)因为 ()在代码中执行权最高  里面的inner读到func 里的地址 保存下来 
但是没有执行 然后执行return 把inner的地址返回并赋值给login 现在调用login() 就等于执行了 inner()
然后执行里面你添加的代码 最后读到func()的时候执行 login
因为现在的这个func指向的地址就是当初你传进来的那个 login的地址 现在加了括号就可以直接运行了.

这段代码还可以优化 就是加装饰器语法糖@

例如

def outer(func):
      def inner(*args,**kwargs):
            user_name=input("输入账号").strip()
            if user_name != '':
                res=func(*args,kwargs)
                return res
    return inner


@outter   这个语法糖相等于 login=outer(login) 这样你使用就可以直接调用了 不需要再写了 提升 他只会找离自己最近的那个:会将紧挨着它的可调用对象的名字当做参数自动传入调用outter
def login (name):
       print('登录成功')
       print('欢迎',name)    

但是他最后调用的那个login() 他的地址其实是指向 inner 因为他只是覆盖了名字 地址却没有改变 那么怎么办呢

python自带一个 模块可以处理这个问题 装饰器修复技术 可以返回原来的函数名 返回原来函数的注释

    from functools import wraps #这个就是那个模块了 用的时候 在第二层写@wraps
    def outter(func):
        @wraps(func)
        def inner(*args,**kwargs):  # * **在形参中使用
            # 执行被装饰函数之前你可以做的操作
            res = func(*args,**kwargs)  # * **在实参中使用
            # 执行被装饰函数之后你可以做到操作
            return res
        return inner

    @outter
    def index(username,*args,**kwargs):
        """index注释"""
        pass
    print(index)

多层装饰器

  

总结
1 要想装饰器不修改被装饰函数的返回值,我们需要在装饰器中接受被装饰函数的返回值并Return即可。

2 如果希望对被装饰函数进行分类处理,我们可以在绑定装饰器时传入一个参数用于对被装饰函数进行分类,但是这样我们需要在装饰器中在套一层函数,在第一层接收装饰器传递的参数,在第二层函数中接收被装饰函数。

3 如果希望装饰器既能装饰带参的函数也可以修饰不带参的函数,我们只需要在装饰器中接收参数时,把参数定义为非固定参数即可。

 

posted @ 2019-07-12 16:59  LD_Dragon  阅读(275)  评论(0编辑  收藏  举报