• python函数闭包和装饰器


    关于问题的注意事项

    nonlocal 的问题

    nonlocal的变量范围问题,可以获取上层函数的变量,如果上层函数没有这个变量,那么会到上上层找,但不会到全局找.

    示例如下:

    def fun():
        a = 1
        def fun2():
            a = 2
            def fun3():
                nonlocal a
                print(a)
            fun3()
        fun2()
    fun()
    
    """
    运行结果
    不注释a=2时话是2,注释后是1
    """

    关于全局作用域和局部作用域的问题

    示例:

    def fun():
        a = 1
        def fun2():
            a += 1
            print(a)
        fun2()
    fun()
    """
    这里会报错的,因为如果在局部一但赋值操作,python解释器就会认为是局部变量,局部变量的话,需要先赋值
    """

    关于dic增加的j时dic.setdefault("key","value")

    这个dic.setdefault("key","value")有增另键值对的功能 ,这里需要注意到的是,这个会有返回.返回的值是value的值.

    由于setdefault这个值,当字典中存在这个key时,这次的增加是无效的,但是这个会返回现在字典中这个key的value值.如果不存在key会返回setdefault设置的value值.

    示例如下:

    dic = {}
    dic.setdefault("key","value")
    print(dic)
    
    """
    这个是增加字典的键值
    
    """

    关于**kwargs 这个值,不能传入**{3:4}这样的值,因为传参相当于变量,变量不能接受纯数字当变量的.

    示例:

    def func(**kwargs):
        print(kwargs)
        
    def(**{"a":2,"b":3},**{3:4})

    关于函数默认赋值的深坑

    def func(a,lst = []):

      lst.append(a)

      return lst

    如下问题:

    lst1 = func("10")

    lst2 = func("20",[])

    lst3 = func("30")

    最后print(lst1,lst2,lst3)

    下面是运行结果

    ['10', '30'] ['20'] ['10', '30']

    原因是当形参传入可变值时,python解释器会分配一个对像,这个对像是不变的,当多次调这个函数时,指向的是同一个地址.所以函数默认传参应该尽量传入可hash的,也就是不可变类型的.

    上面是补充,补充完毕

    本节主要内容: 1. 函数名的运⽤, 第⼀类对象 2. 闭包 3. 装饰器初识

     1. 函数名的运⽤, 第⼀类对象 

    函数名是一个变量,但它是一个特殊的变量加个()是可以执行的变量

    函数名有 以下特性:

    1)函数名是一个内存地址,

    示例:

    def fun():
        print(100)
    print(fun)

    上面的代码是打印函数的内存地址.

    2)函数名可以赋值给其他变量

    示例:

    示例是把函数名赋值给b,然后b执行了这个函数

    def fun():
        print(100)
    
    b = fun
    b()

    3)函数名可以当做容器类的元素

    函数名可以当做其他容器类的无素,容器类如,列表,字典等

    示例:

    def fun1():
        print("1")
    def fun2():
        print("2")
    def fun3():
        print("3")
    lst = [fun1,fun2,fun3]
    for e in lst:
        print(e)
    
    """
    变量名只是内存地址,循环调用的话,只是显示了内存地址
    """

    4.函数名可以当做函数的参数

    示例:

    def fun():
        print("呵呵")
    def fun1(fn):
        fn()
    fun1(fun)

    5. 函数名可以作为函数的返回值

    示例:

    def fun():
        def inner():
            print("123")   
        return inner
    f = fun()
    f()
    """
    函数的返回
    """

    ⼆. 闭包

     什么是闭包? 闭包就是内层函数, 对外层函数(非全局)的变量的引⽤. 叫闭包

    示例:

    def fun():
        a = 1
        def inner():
            print(a)
        inner()
    fun()

    可以通过__closure__来查看内层函数是否闭包    __closure__  返回none表示不是闭包,返回cell是闭包

    如何在函数外部调用闭包,下面是示例

    def fun():
        a = 1
        def inner():
            print(a)
        inner()
        return inner
    f = fun()
    print(f.__closure__)

    这里会涉及到函数的多层嵌套,如下

    def func1():
        def func2():
            def func3():
                print("嘿嘿")
            return func3
        return func2
    func1()()()

    由它我们可以引出闭包的好处. 由于我们在外界可以访问内部函数. 那这个时候内部函 数访问的时间和时机就不⼀定了, 因为在外部, 我可以选择在任意的时间去访问内部函数. 这 个时候. 想⼀想. 我们之前说过, 如果⼀个函数执⾏完毕. 则这个函数中的变量以及局部命名 空间中的内容都将会被销毁. 在闭包中. 如果变量被销毁了. 那内部函数将不能正常执⾏. 所 以. python规定. 如果你在内部函数中访问了外层函数中的变量. 那么这个变量将不会消亡. 将会常驻在内存中. 也就是说. 使⽤闭包, 可以保证外层函数中的变量在内存中常驻. 这样做 有什么好处呢? 非常⼤的好处. 我们来看⼀个关于爬⾍的代码:

    三. 装饰器初识

    装饰器的作⽤就是在不修改原有代码的基础上, 给函数扩展功能.

    示例:

    如果现在有函数:

    def create_people():
        print("⼥娲很厉害. 捏个泥⼈吹⼝⽓就成了⼈了")

    想要在不修改这个函数调用的基础上实现增加功能.这个可以采用下面的方法

    def wrapper(fn):

      def inner():

        #开始增加的功能

        fn()

        #结束要增加的功能

      return inner

    create_people = wrapper(create_people)

    这边来描述一下装饰器执行的原理

    1.先写好装饰器函数,

    2.调用装饰器,传入函数名,

    3,把原有的函数改名

    4.调用原有的函数名,

    5.实际上是调用wrapper(func)()

    6.也就是装饰器的内置函数

    结论: 我们使⽤warter函数把create_people给包装了⼀下. 在不修改create_people的前提下. 完成了对create_people函数的功能添加

    下面是语法糖格式

    示例:

    def wrapper(fn):
        def inner():
            #开始增加的功能
            print("夏天来了")
            fn()
            print("冬天来了")
        return inner
    
    
    @wrapper
    def create_people():
        print("⼥娲很厉害. 捏个泥⼈吹⼝⽓就成了⼈了")
    create_people()

     下面是装饰器完整模型代码,

    def wrapper(fn):

      def inner(*args,**kwargs):

        #前面要加的代码

        ret = fn(*args,**kwargs)

        #后面要加的代码

        return ret

      return inner

    @wrapper

    示例

    def wrapper(fn):
        def inner(*args,**kwargs):
            #前面执行的代码
            ret = fn(*args,**kwargs)
            #后面执行的代码
            return ret
        return inner
    @wrapper
  • 相关阅读:
    程序员学习视频教程汇总
    分享一个单机软件试用期计时思路
    C# XML转Json Json转XML XML 转对象 对象转XML
    C# 数独 解法
    C# 炸弹人 winform版
    胃食管反流疾病认识总结
    C# Datagridview combox列 初始化颜色
    C# WPF 坦克大战
    高分辨率食道测压(HRM)
    C# wpf 使用 polyline 做一个贪吃蛇游戏的小蛇移动吃食部分功能
  • 原文地址:https://www.cnblogs.com/ahliucong/p/9183274.html
Copyright © 2020-2023  润新知