天天看點

【小甲魚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']
>>>