020,函数:内嵌函数与闭包

020,函数:内嵌函数与闭包

 
回顾: 
>>>  count  =  5        #全局变量
>>>  def  MyFun ( ) :
     count  =  10            #局部变量
     print ( 10 )
 
    
>>>  MyFun ( )            #读取局部变量
10
>>>  print ( count )        #打印全局变量(等于是屏蔽了局部变量)
5
>>> 
 
 global关键字  
>>>  def  MyFun ( ) :
     global  count            #告诉编译器把这个count变成全局变量
     count  =  10
     print ( 10 )
 
    
>>>  MyFun ( )
10
>>>  print ( count )
10
>>> 
 
内嵌函数(允许在函数内部创建另一个函数,叫内部函数)  
>>>  def  fun1 ( ) :
     print ( 'fun1()正在被调用。。' )
     def  fun2 ( ) :
         print ( 'fun2()正在被调用。。。。' )
     fun2 ( )
 
    
>>>  fun1 ( )
fun1 ( ) 正 在 被 调 用 。 。
fun2 ( ) 正 在 被 调 用 。 。 。 。
>>>  fun2 ( )
Traceback  ( most  recent  call  last ) :
   File  "<pyshell#18>" ,  line  1 ,  in  < module >
     fun2 ( )
NameError :  name  'fun2'  is  not  defined
>>> 
注意:内部函数的整个作用域都在外部函数之内,如fun2整个定义和调用的过程都在fun1里面,除了在fun1里可以任意调用,出了fun1之外无法被调用,会系统报错

闭包——函数式编程的重要语法结构。
如果在一个内部函数被外部作用域(但不是全局作用域的变量)进行引用,那么内部函数会被认为是闭包  
>>>  def  funX ( x ) :    # 外 部 作 用 域  的 变 量  x
     def  funY ( y ) :    # 内 部 函 数 ( 闭 包 )
         return  x  *  y      # 引用了x 变 量
     return  funY
 
>>>  i  =  funX ( 8 )      #类似直接调用funX(8)      
>>>  i
< function  funX . < locals > . funY  at  0x022E5738 >
>>>  type ( i )
< class  'function' >
>>>  i ( 5 )            #等同 (funX(8))(5)
40
>>>  funX ( 8 ) ( 5 )
40
>>> 
 
报错例子:  
>>>  def  fun1 ( ) :
     x  =  5
     def  fun2 ( ) :
         x  *=  x
         return  x
     return  fun2 ( )
 
>>>  fun1 ( )
Traceback  ( most  recent  call  last ) :
   File  "<pyshell#45>" ,  line  1 ,  in  < module >
     fun1 ( )
   File  "<pyshell#44>" ,  line  6 ,  in  fun1
     return  fun2 ( )
   File  "<pyshell#44>" ,  line  4 ,  in  fun2
     x  *=  x
UnboundLocalError :  local  variable  'x'  referenced  before  assignment   #这里错误提示,在fun2()里,x在没有被赋值之前不能被引用。
>>>
 改造:
 在python2.x里可以投机取巧用列表实现x的调用  
>>>  def  fun1 ( ) :
     x  =  [ 5 ]
     def  fun2 ( ) :
         x [ 0 ]  *=  x [ 0 ]
         return  x [ 0 ]
     return  fun2 ( )
 
>>>  fun1 ( )
25
>>> 
 在python3.x中,用关键字:nonlocal  
>>>  def  fun1 ( ) :
     x  =  5
     def  fun2 ( ) :
         nonlocal  x
         x  *=  x
         return  x
     return  fun2 ( )
 
>>>  fun1 ( )
25
>>> 
 

测试题:
      
0. 如果希望在函数中修改全局变量的值,应该使用什么关键字?
答:global  
>>>   count   =   5
>>>   def   MyFun ( ) :
                    global   count
                    count   =   10
                    print ( count )
 
>>>   MyFun ( )
10
>>>   count
10
 


1. 在嵌套的函数中,如果希望在内部函数修改外部函数的局部变量,应该使用什么关键字?
答: nonlocal 
举个例子:
  1. >>> def Fun1():
  2.                 x = 5
  3.                 def Fun2():
  4.                         nonlocal x
  5.                         x *= x
  6.                         return x
  7.                 return Fun2()
  8. >>> Fun1()
  9. 25

2. Python的函数可以嵌套,但要注意访问的作用域问题哦,请问以下代码存在什么问题呢?
  1. def outside():
  2.     print('I am outside!')
  3.     def inside():
  4.         print('I am inside!')
  5. inside()
     答:inside()是内部函数,不能在外部调用
使用嵌套函数要注意一点就是作用域问题,inside()函数是内嵌在outside()函数中的,所以inside()是人妻,除了身为老公的outside()可以碰(调用),在外边或者别的函数体里是无法对其进行调用的。(这老师真邪恶)

3. 请问为什么代码A没有报错,但代码B却报错了?应该如何修改?

代码A:
  1. def outside():
  2.     var = 5
  3.     def inside():
  4.         var = 3
  5.         print(var)
  6.         
  7.     inside()
  8. outside()
复制代码
代码B:
  1. def outside():
  2.     var = 5
  3.     def inside():
  4.         print(var)
  5.         var = 3
  6.         
  7.     inside()
  8. outside()
答:UnboundLocalError: local variable 'var' referenced before assignment   代码B中 在inside()里先执行print(var)语句,这是var是外部变量,没有在inside()里定义,故报错。
仔细一看报错的内容是:UnboundLocalError: local variable 'var' referenced before assignment,说的是变量var没有被定义就拿来使用,肯定错啦!

这里outside()函数里有一个var变量,但要注意的是,内嵌函数inside()也有一个同名的变量,Python为了保护变量的作用域,故将outside()的var变量屏蔽起来,因此此时是无法访问到外层的var变量的。

应该修改为:
  1. def outside():
  2.     var = 5
  3.     def inside():
  4.         nonlocal var
  5.         print(var)
  6.         var = 8
  7.         
  8.     inside()
  9. outside()

4. 请问如何访问funIn()呢?
  1. def funOut():
  2.     def funIn():
  3.         print('宾果!你成功访问到我啦!')
  4.     return funIn()
答:funOut()

5. 请问如何访问funIn()呢?
  1. def funOut():
  2.     def funIn():
  3.         print('宾果!你成功访问到我啦!')
  4.     return funIn
 答:funOut()()

6. 以下是“闭包”的一个例子,请你目测下会打印什么内容?
  1. def funX():
  2.     x = 5
  3.     def funY():
  4.         nonlocal x
  5.         x += 1
  6.         return x
  7.     return funY
  8. a = funX()
  9. print(a())
  10. print(a())
  11. print(a())
 答:不在idle测试,目测 
6
7
8
有些鱼油可能会比较疑惑,这……怎么跟全局变量一样了?局部变量x不是应该在每次调用的时候都重新初始化了吗?!

其实大家仔细看看就明白了,当a = funX()的时候,只要a变量没有被重新赋值,funX()就没有被释放,也就是说局部变量x就没有被重新初始化。

所以当全局变量不适用的时候,可以考虑使用闭包更稳定和安全,你还可以参考 ->  游戏中的角色移动:闭包在实际开发中的作用  

动动手:(这个比较难,先复习之前的知识过后才着手练习。)
     
0. 请用已学过的知识编写程序,统计下边这个长字符串中各个字符出现的次数并找到小甲鱼送给大家的一句话。
(由于我们还没有学习到文件读取方法,大家下载后拷贝过去即可)  
答:前面 定义了一个变量叫 txt = 文件里的所有字符  
def  count ( ) :
    # 判 断 各 种 特 殊 字 符 分 别 在 文 本 中 出 现 的 次 数
     symbols  =  r '''`!@#$%^&*()_+-=/*{}[] \| '";:/?,.<>'''
     letters  =  'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
    # 迭代symbols 中 的 每 个 字 符
     for  each  in  symbols :
        # 判断字符是否在txt 文 件 中 , 如 果 是 , 则 计 算 该 字 符 在 文 本 中 一 共 有 几 个            
         if  each  in  txt :
              num  =  txt . count ( each )
              print ( '字符 %s 在文本当中一共出现了%d 次'  %  ( each , num ))
    # 找 出 字 母 并 打 印
     for  each2  in  txt :      # 如果这里换成for  each2  in  letters那么打印出来的字母是按照letters 里 的 排 序 顺 序 出 现 的  
         if  each2  in  letters :
              print ( each2 , end  =  '' )
 
count ( )
 论坛参考答案:  
str1  =  '''拷贝过来的字符串'''
list1  =  [ ]
 
for  each  in  str1 :
     if  each  not  in  list1 :
         if  each  ==  ' \n ' :
              print ( ' \\ n' ,  str1 . count ( each ))
         else :
              print ( each ,  str1 . count ( each ))
         list1 . append ( each )
 不明觉厉!!!!
 


1. 请用已学过的知识编写程序,找出小甲鱼藏在下边这个长字符串中的密码,密码的埋藏点符合以下规律:
    a) 每位密码为单个小写字母
    b) 每位密码的左右两边均有且只有三个大写字母
(由于我们还没有学习到文件读取方法,大家下载后拷贝过去即可)  
 答: 前面 定义了一个变量叫 txt = 文件里的所有字符 ------------我居然没用到函数。。。。
length  =  len ( txt )
for  i  in  range ( length ) :
     if  txt [ i ] . islower ( )  and  txt [( i +1 ) : ( i +4 )] . isupper ( )  and  txt [( i -3 ) : ( i )] . isupper ( )  :
         print ( txt [ i ] , end  =  '' )
 
论坛参考答案:
  1. str1 = '''拷贝过来的字符串'''
  2. countA = 0
  3. countB = 0
  4. countC = 0
  5. length = len(str1)
  6. for i in range(length):
  7.     if str1[i] == '\n':
  8.         continue
  9.     if str1[i].isupper():
  10.         if countB == 1:
  11.             countC += 1
  12.             countA = 0
  13.         else:
  14.             countA += 1
  15.         continue
  16.     if str1[i].islower() and countA == 3:
  17.         countB = 1
  18.         countA = 0
  19.         target = i
  20.         continue
  21.     if str1[i].islower() and countC == 3:
  22.         print(str1[target], end='')
  23.     countA = 0
  24.     countB = 0
  25.     countC = 0
 
 
 总结,我怎么觉得操作题自己写的代码比论坛参考答案还简洁一些呢?!

转载于:https://www.cnblogs.com/fishdm/p/3574069.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。
经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值