课时20:内嵌函数和闭包

目录:

  一、global关键字

  二、内嵌函数

  三、闭包

  四、课时20课后习题及答案

********************

一、global关键字

********************

全局变量的作用域是整个模块(整个代码段),也就是代码段内所有的函数内部都可以访问到全局变量。但是要注意一点,在函数内部仅仅去访问全局变量就好,不要试图去修改它。

因为那样的话,Python会使用屏蔽的方式”保护“全局变量:一旦函数内部试图修改全局变量,Python就会在函数内部自动创建一个名字一模一样的局部变量,这样修改的结果只会修改到局部变量,而不会影响到全局变量。看下面的例子:

>>> count=5
>>> def myFun():
    count = 10
    print(count)

    
>>> myFun()
10
>>> count
5

如果觉得有必要在函数中去修改这个全局变量,那么你不妨可以使用global关键字来达到目的!修改程序如下:

>>> count=5
>>> def myFun():
    global count
    count = 10
    print(count)

    
>>> myFun()
10
>>> count
10

二、内嵌函数

****************

 Python函数定义是可以嵌套的,也就是允许在函数的内部创建另外一个函数,这种函数叫做内嵌函数或者内部函数。举个例子:

>>> def fun1():
     print("fun1()正在被调用")
     	def fun2(): 
        	print("fun2()正在被调用") 
    	fun2()
>>> fun1() 
fun1()正在被调用 
fun2()正在被调用 

值得注意的是:就是内部函数整个作用域都在外部函数之内。

另外需要注意的地方:如果在fun1()外部试图调用内部函数fun2(),就会报错:

>>> fun2()
Traceback (most recent call last):
  File "<pyshell#45>", line 1, in <module>
    fun2()
NameError: name 'fun2' is not defined

***********

三、闭包

***********

 闭包是函数编程的一个重要的语法结构,函数式编程是一种编程范式,著名的函数式编程语言就是LISP语言。

Python中闭包从表现形式上定义为:如果在一个内部函数内(funY就是这个内部函数),对外部作用域(但不是在全局作用域)的变量进行引用(x就是被引用的变量,x在外部作用域funX里面,但不在全局作用域里),那么内部函数就被认为是闭包。

>>> def funX(x):
	    def funY(y):
	        return x*y
            return funY

>>> i = funX(8)
>>> i
<function funX.<locals>.funY at 0x0000017296857488>
>>> type(i)
<class 'function'>
>>> type(funX)
<class 'function'>
>>> funX
<function funX at 0x0000017296857598>
>>> i(5)
40

也可以直接这样写:

>>> funX(8)(5)
40

使用闭包时,需要注意的是:因为闭包的概念就是由内部函数而来的,所以也不能在外部函数以外的地方对内部函数进行调用:

>>> funY(5)
Traceback (most recent call last):
  File "<pyshell#58>", line 1, in <module>
    funY(5)
NameError: name 'funY' is not defined

在闭包中,外部函数的局部变量对应内部函数的局部变量,实际上就相当于之前讲的全局变量跟局部变量的关系,在内部函数中,你只能对外部函数的局部变量进行访问,但不能进行修改。

>>> def funX():
    x = 5
    def funY():
        x *= x
        return x
    return funY

>>> funX()()
Traceback (most recent call last):
  File "<pyshell#61>", line 1, in <module>
    funX()()
  File "<pyshell#60>", line 4, in funY
    x *= x
UnboundLocalError: local variable 'x' referenced before assignment

这个错误信息跟之前讲解全局变量的时候基本一样,Python认为在内部函数的x是局部变量的时候,外部函数的x就被屏蔽了起来,所以执行x *= x的时候,在右边根本找不到局部变量x的值,因此报错。

在Python3以前并没有直接的方案进行解决,只能间接的通过容器类型来存放,因为容器类型不是放在栈里,所以不会被‘屏蔽’掉。

>>> def funX():
    x = [5]
    def funY():
        x[0] *= x[0]
        return x[0]
    return funY

>>> funX()()
25

在Python3里有了改进。如果希望在内部函数里可以修改外部函数里的局部变量的值,用关键字nonlocal。

>>> def funX():
    x = 5
    def funY():
        nonlocal x
        x *= x
        return x
    return funY

>>> funX()()
25

扩展阅读–>游戏中的移动角色:闭包在实际开发中的作用:(地址是:https://fishc.com.cn/thread-42656-1-1.html

*******************************

四、课时20课后习题及答案

*******************************

global

代码:
num = 5
def printnum():
    global num
    print(num)

printnum()

运行结果:
5

代码:
num = 5
def printnum():
    global num
    num = 10
    print(num)

printnum()

运行结果:
10

nonlocal

def funX():
    x = 5
    def funY():
        nonlocal x
        x += 10
        return x
    return funY()

print(funX())

运行结果:
15
代码一:
def outside():
    print('outside!')
    def inside():
        print('inside!')

inside()

运行结果:
Traceback (most recent call last):
  File "C:/Users/Arenas/Documents/Python Code/JiaYu/lesson20/outin.py", line 12, in <module>
    inside()
NameError: name 'inside' is not defined

代码二:
def outside():
    print('outside!')
    def inside():
        print('inside!')
    return inside

outside()()
运行结果:
outside!
inside!
我的代码:
def outside():
    var = 5
    def inside():
        nonlocal var
        print(var)
        var = 3
    inside()

outside()

运行结果:
5
funOut()
funOut()()
或者
go = funOut()
go()
>>> def funX():
	x = 5
	def funY():
		nonlocal x
		x += 1
		return x
	return funY

>>> a = funX()
>>> print(a())
6
>>> print(a())
7
>>> print(a())
8
代码:
str1 = '''
sdsdsdsdsdsd
fdsfsdfsdf
sdfsdf
dsfsdfsdf
sdfsdf
sdfsdf
sdfsdf
dsfsdfsdfg
'''
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)

print(list1)

运行结果:
n 9
s 23
d 23
f 18
g 1
['n', 's', 'd', 'f', 'g']
小甲鱼代码:
str1 = '''
sdsdsdsdsdsd
fdsfsdfsdf
AABsCCCdCCDc
AAAvFFFsdfsdf
sdVVVfVVVsdf
sdfsdf
dsfsdfsdfg
'''
count_Upper_Left = 0
count_Lower_Single = 0
count_Upper_Right = 0
length = len(str1)

for i in range(length):
	if str1[i] == 'n':
		continue
	if str1[i].isupper():
		if count_Lower_Single == 1:
			count_Upper_Right += 1
			count_Upper_Left = 0
		else:
			count_Upper_Left += 1
		continue
	if str1[i].islower() and count_Upper_Left == 3:
		count_Lower_Single = 1
		count_Upper_Left = 0
		target = i
		continue
	if str1[i].islower() and count_Upper_Right == 3:
		print(str1[target],end='')
	count_Upper_Left = 0
	count_Lower_Single = 0
	count_Upper_Right = 0

运行结果:
scf

我的代码:
str1 = '''
sdsdsdsdsdsd
fdsfsdfsdf
AABsCCCdCCDc
AAAvFFFsdfsdf
sdVVVfVVVsdf
sdfsdf
dsfsdfsdfg
'''

length = len(str1)
for i in range(2,(length-1)):
	if str1[i].islower():
		if str1[i-1].isupper() and str1[i-2].isupper() and str1[i-3].isupper():
			if str1[i+1].isupper() and str1[i+2].isupper() and str1[i+2].isupper():
				print(str1[(i-3):(i+4)])

运行结果:
AABsCCC
CCCdCCD
AAAvFFF
VVVfVVV
  • global
  • 闭包
  • nonlocal
  • return funY – 因为容器类型不是放在栈里,所以不会被‘屏蔽’掉
  • funX()()和funX() -课后习题第4题和第5题

发表回复