天天看点

【小甲鱼Python】函数:内嵌函数和闭包&&课后作业笔记课后作业

笔记

global关键字

【小甲鱼Python】函数:内嵌函数和闭包&&课后作业笔记课后作业

格式:global 变量名  ;使该变量变为全局变量。

内嵌函数

在一个函数(外部函数)内部嵌套定义另一个函数。

内部函数的整个作用域全都且只在外部函数内,即只能在外部函数内调用内部函数,不可以在外部函数外调用内部函数。

外部函数与内部函数两者局部变量之间的关系,就如同之前所讨论的全局变量与局部变量之间的关系。

【小甲鱼Python】函数:内嵌函数和闭包&&课后作业笔记课后作业
【小甲鱼Python】函数:内嵌函数和闭包&&课后作业笔记课后作业

如上图,Fun2()中试图改变外部函数Fun1的局部变量x,此时屏蔽机制使得Python在Fun2的栈中自动创建一个新的局部变量x,新的x没有赋值,从而导致程序报错。

解决方法:

方法一:在老版的Python中,需要通过容器类型的变量进行解决,因为容器类型的变量不是存放于栈中的。如下图:

【小甲鱼Python】函数:内嵌函数和闭包&&课后作业笔记课后作业

方法二:使用nonlocal()

【小甲鱼Python】函数:内嵌函数和闭包&&课后作业笔记课后作业

注:global是把局部变量转换为全局变量;nonlocal是把内部函数的局部变量转换为外部函数的局部变量。

闭包(closure)

函数式的重要语法结构。

我们可以将闭包理解为一种特殊的函数,这种函数由两个函数的嵌套组成,且称之为外函数和内函数,外函数返回值是内函数的引用,此时就构成了闭包。

参考链接:https://blog.csdn.net/weixin_44141532/article/details/87116038

                  https://baijiahao.baidu.com/s?id=1601023189180094497&wfr=spider&for=pc

如何对形成闭包的内部函数进行调用?

例如有如下闭包:

【小甲鱼Python】函数:内嵌函数和闭包&&课后作业笔记课后作业

方式一(“曲线救国”):

【小甲鱼Python】函数:内嵌函数和闭包&&课后作业笔记课后作业

可见FunX(8)返回的是一个函数对象,并赋值给i,使i也变为函数,再对i进行调用,即调用了内部函数。

方式二(直接调用):

【小甲鱼Python】函数:内嵌函数和闭包&&课后作业笔记课后作业

内函数的引用

对比如下两例(取自课后作业测试题第5,6题):

def funOut():
    def funIn():
        print('宾果!你成功访问到我啦!')
    return funIn
           
def funOut():
    def funIn():
        print('宾果!你成功访问到我啦!')
    return funIn()
           

前者为闭包,使用上文所述的两种方式均可。

后者则直接调用 funOut()即可。

课后作业

https://fishc.com.cn/forum.php?mod=viewthread&tid=42685&page=1

测试题:

0.答:global关键字。

1.答:nonlocal关键字。

2.答:一方面,在函数outside中没有对inside进行调用,使得inside的定义毫无意义;另一方面,inside属于内部函数,只能在其外部函数outside中进行调用,不能在外部函数外面调用。

3.答:

原因:对于代码B,在inside中,由于局部变量var与其外部函数中的局部变量var重名。根据Python的屏蔽机制,inside中会重新在其栈内创建一个同名的新变量var,而此时var还未赋值就被print调用,自然会报错。而对于代码A,则会正常输出3。

修改:

def outside():
    var = 5
    def inside():
        nonlocal var
        print(var)
        var = 3
        
    inside()
outside()
           

4.答:

直接调用funOut()即可:

funOut()
宾果!你成功访问到我啦!
           

5.答:

方式一:

i = funOut()
i()
           

方式二:

funOut()()
           

6*.

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

a = funX()
print(a())
print(a())
print(a())
           

答:

6
7
8
           

注:a = funX()并不意味着funX()执行完了。只要 a 变量没有被重新赋值,funX() 就没有被释放,也就是说局部变量 x 就没有被重新初始化。所以当全局变量不适用的时候,可以考虑使用闭包更稳定和安全。你还可以参考 -> 游戏中的角色移动:闭包在实际开发中的作用。

动动手:

0.答:

string = '''拷贝过来的字符串'''
list1 = list(string)
char = []
answer = []
for each in string:
    if each not in char:
        char.append(each)
for each in char:
    if each == '\n':
        print('\\n字符出现了%d次'%string.count(each))
    else:
        print('%s字符出现了%d次'%(each,string.count(each)))
for each in char:
    if each.isalnum():
        answer.append(each*string.count(each))
print(answer)
           

输出:

%字符出现了6104次
$字符出现了6046次
@字符出现了6157次
_字符出现了6112次
^字符出现了6030次
#字符出现了6115次
)字符出现了6186次
&字符出现了6043次
!字符出现了6079次
+字符出现了6066次
]字符出现了6152次
*字符出现了6034次
}字符出现了6105次
[字符出现了6108次
(字符出现了6154次
{字符出现了6046次
\n字符出现了1219次
G字符出现了1次
O字符出现了2次
D字符出现了1次
L字符出现了1次
U字符出现了1次
C字符出现了1次
K字符出现了1次
['G', 'OO', 'D', 'L', 'U', 'C', 'K']
           

1.答:

string = '''此处为文本内容'''

def ispassword(char_index):
    if char.islower():
            j = 0
            for i in range(1,4):
                if string[char_index + i].isupper() and string[char_index - i].isupper():
                    j += 1
            if char_index > 3 and char_index < (length - 3):
                if string[char_index + 4].islower() and string[char_index - 4].islower():
                    j += 1
                if j == 4:
                    list1.append(char)
            elif char_index == 3 and char_index == (length - 3) and j == 3:
                    list1.append(char)
list1 = []
length = len(string)
char_index = 3 #从第四个字符开始查找
char = string[char_index] 

ispassword(char_index)  #判断第四个字符是否为密码

for char in string[4:length - 3]:   #判断第5——length-4之间的字符是否为密码
    char_index += 1
    ispassword(char_index)
                
char = string[length - 3]  #判读第length-3个字符是否为密码
ispassword(char_index)
           

密码存储在list1中:

>>> list1
['i', 'l', 'o', 'v', 'e', 'f', 'i', 's', 'h', 'c']
>>>