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

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

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

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

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

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

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

     

二.内置函数

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

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

  代码示例如下:

扫描二维码关注公众号,回复: 1786279 查看本文章

  

  可以看到:无论在哪个位置,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:加入返回值:

  

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

  装饰器的格式:

  

  

猜你喜欢

转载自www.cnblogs.com/moranlei/p/9172547.html
今日推荐