• python 笔记(名称空间、内置函数、闭包、装饰器)


    一.名称空间、作用域、取值顺序等。

      1.(1)名称空间:当程序开始运行时,代码自上而下开始依次执行,他会将变量与值的对应关系存储在一个空间中,这个空间就叫名称空间,命名空间,全局名称空间,当程序遇到函数时,他会将函数名存在内存中,函数体莫不关心。当函数执行时,内存会临时开辟一个空间,存放函数体里面的代码(变量,代码等),函数外面访问不到临时空间的内容,随着函数的执行完毕,临时名称空间会释放掉,向这个临时开辟的空间叫临时名名称空间,也叫局部名称空间。

      (2)python 中名称空间分三种:
          内置名称空间。
          全局名称空间。
          局部名称空间。

      (3)作用域:全局作用域:
             内置名称空间。
             全局名称空间。
         (4)局部作用域
             局部名称空间。

         (5)加载顺序:
            内置名称空间 ---> 全局名称空间(当程序执行时) ---> 局部名称空间(当函数调用时)
         (6)取值顺序:单向不可逆
             局部名称空间(当函数调用时) -->全局名称空间(当程序执行时) -->内置名称空间

      (7).函数的嵌套操作:也就是说函数里面可以在定义多个函数嵌套起来使用,示例如下:

         

    二.内置函数

      1.内置函数的两个关键词:

      globals() 返回一个字典,字典里面的内容是全局作用域的内容。
      locals():返回一个字典,当前位置 的所有变量。

      代码示例如下:

      

      可以看到:无论在哪个位置,globals()打印出来的都是全局作用域的内容,而locals()就不一样,在函数里边,locals()打印的是函数里边的局部变量,而在函数外边则打印出来的是当前位置的全局变量。

      案例二代码:

      

      这里的答案就相当明显了:global()未打印出,因为当前没有全局变量,而locals打印出了当前位置的局部变量:name1和age1

    三.全局变量和局部变量的使用:

      这里先重复上一个概念:取值顺序:单向不可逆
         局部名称空间(当函数调用时) -->全局名称空间(当程序执行时) -->内置名称空间

      这里有两个关键词:global和nonlocal

       (1).global:引用并改变一个全局变量,在局部作用域声明一个全局变量:

      先看这样一个例子:

      

       

      这样看程序是报错的,而报错原因是因为在函数里边并没有定义count变量,count = 1只是定义的一个全局变量,在函数里边并不能调用的到,但如果我们想用呢?这里就用到了global这个关键字:

       

      这样,代码就能正常执行啦,global 的作用就是引用并改变一个全局变量,在局部作用域声明一个全局变量。

      当然也可以在局部变量里声明变量,让它当做全局变量来使用:

      

      (2)nonlocal:不能操作全局变量,从那层引用就从那层开始改变:

      

      取值:引用而不是改变
          取值是从小到大取值 LEGB
            想改变上层空间的变量 要用到global nonlocal

     (3).对于可变的数据类型,dict、list、set不能使用global/nonlocal参数。

      

      如果默认参数是一个可变的数据类型,那么他在内存中永远是一个

      

    四.函数名的应用。

      (1).打印函数名:

      

     (2).函数名可以作为容器类数据的元素:

      

      (3).函数名可以作为函数的参数传递进来:

      

      (4).函数名可以作为函数的返回值:

      

    五.闭包:

      (1).闭包:内层函数对外层函数非全局变量的引用,就叫做闭包

      

      这里的inner函数就是内层函数,调用的name变量就是对外层函数非全局变量的引用。

      这里有一个.__closure__方法就是判断是不是闭包,如果打印出cell之类的信息就是闭包,如下:

      

      如果 python 解释器遇到了闭包,他有一个机制,这个闭包不会随着函数的结束而释放。

    六.装饰器:

      (1).什么是装饰器,装饰器本质就是闭包,就是在不影响原函数功能的前提下,增加一些额外的功能,如打印日志,执行输出的一些功能,接下来一步步引入装饰器的概念:

      有这样的这一个需求:假设要测试一个函数的执行效率(即运行这个函数需要多长时间),我们首先想到的应该是这个样子:

       版1:

      

      这个时候你可能会发现这样程序不具有模块化,要将测试函数用函数封装起来更好一点:

      版2:

      

      这个时候又有问题了,假设有1000个测试函数,那我岂不是要写1000个timer函数,太冗余了,何不把测试函数当成一个参数传递进来呢,这就会更便捷一点:

      版3:将测试函数以参数的形式传递进来

      

      这个时候又有问题了,试想:我每测试一个函数就要按照这样的格式去写,那是不是就改变了我原有函数的执行方式了呢?这样不好,再次进行改版:

      版4:尽量不要改变原来函数的执行方式

      

      这样虽然大致满足了我的需求,但是调用的时候还是多传递了一个参数进来,这样不太好,有没有一种方法,不改变他的调用方式呢?继续改版

      版5:不改变原来函数的运行方式:

      

      这个时候就基本满足我们的要求啦,也没有改变原有函数的调用方式,但每次调用前我们总要先执行 fun = timer(fun)函数,太麻烦啦,python里边提供一个@符号也就是语法糖的概念代替这一句话:

      版6:引入语法糖:

      

      这样程序及基本算完事啦,还有一个问题,试想如果人家要测试的函数有参数怎么办?你总不能再次给人家开发一个timer吧,这里我们还需要加上参数

      版7:加入参数

      

      现在参数加进去了,但如果要有返回值该怎么办呢?简单,定义一个参数接收并返回就行了,继续改。。。

      版8:加入返回值:

      

      到这里就是一个完整的装饰器啦,既不需要改变原来函数的调用方式,也具有传递参数、返回值的功能!

      装饰器的格式:

      

      

  • 相关阅读:
    [HAOI2015]按位或
    【bzoj 4675】 点对游戏
    [WC2013]糖果公园
    [国家集训队]数颜色 / 维护队列
    【bzoj 3252】攻略
    [ZJOI2016]小星星
    hdu-1712 ACboy needs your help---分组背包
    hdu-2844&&POJ-1742 Coins---多重背包
    UVA-147 Dollars---完全背包+打表
    hdu-2191 悼念512汶川大地震遇难同胞——珍惜现在,感恩生活---多重背包
  • 原文地址:https://www.cnblogs.com/moranlei/p/9172547.html
Copyright © 2020-2023  润新知