2020年9月15日星期二

[課後作業] 第020講:函數:內嵌函數和閉包|課後測試題及答案

[課後作業] 第020講:函數:內嵌函數和閉包|課後測試題及答案 




《零基礎入門學習Python》視頻下載地址:傳送門uQ{!Ea%
    _l=cfK|b9:zPt2BaHGhimSLRsr
測試題:Powered by bbs.fishc.com
      
0.如果希望在函數中修改全局變量的值,應該使用什麼關鍵字?yYE5${
2$}fOt+Cxi[`:@nJpvoF~dTB4_6-w
sPi=h_o}X#!lO]~"AwG`ntm
1.在嵌套的函數中,如果希望在內部函數修改外部函數的局部變量,應該使用什麼關鍵字?D2Ja!9{Y|f
:+"H?k_8Q&@}a.XGEL|U4%
5#r:u0L-4ndgTc?8'[B
2. Python的函數可以嵌套,但要注意訪問的作用域問題哦,請問以下代碼存在什麼問題呢?<Dy+Zjx](,

  1. def outside():
  2.     print('I am outside!')
  3.     def inside():
  4.         print('I am inside!')

  5. inside()
複製代碼

0<;iw#^h%}&CTQkmgFeqW`]9X
3.請問為什麼代碼A沒有報錯,但代碼B卻報錯了?應該如何修改?av"G+~
<Vh|KPfw_[j4*,#En3cAg>D
代碼A:版權屬於:bbs.fishc.com
  1. def outside():
  2.     var = 5
  3.     def inside():
  4.         var = 3
  5.         print(var)
  6.         
  7.     inside()
  8. outside()
複製代碼

代碼B:來自:bbs.fishc.com
  1. def outside():
  2.     var = 5
  3.     def inside():
  4.         print(var)
  5.         var = 3
  6.         
  7.     inside()
  8. outside()
複製代碼

O-.=*,Psf<]l!YxREn[Gz@&vhCSXu
4.請問如何訪問funIn()呢?[21!iWr
  1. def funOut():
  2.     def funIn():
  3.         print('賓果!你成功訪問到我啦!')
  4.     return funIn()
複製代碼

3!@eabhE^AW8Q7pGj`OmD9y(2v?
5.請問如何訪問funIn()呢?rPgKax8
  1. def funOut():
  2.     def funIn():
  3.         print('賓果!你成功訪問到我啦!')
  4.     return funIn
複製代碼

3x@`7,5n^v-;sb&.I]?{yh|U
6.以下是“閉包”的一個例子,請你目測下會打印什麼內容?Zm)pT]O
  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())
複製代碼

T(H,w25?d;^N)|s7Y@v%xC$JM
Y.JOR@TZ3: NiVP|dLXr*WA]m
動動手:版權屬於:bbs.fishc.com
      -3O(cKsN>%&tQB ^?o!<|ZlJ@u
0.請用已學過的知識編寫程序,統計下邊這個長字符串中各個字符出現的次數並找到小甲魚送給大家的一句話。9cJiUE
.5vZ(7_@ Df4Gn;<O[V}"d09
(由於我們還沒有學習到文件讀取方法,大家下載後拷貝過去即可)R=V:u
-D~^a2(s+>"_TAb}`'RM1L5:kd
請下載字符串文件:  string1.zip (55.49 KB,下載次數: 18670)
     ,h6{:d|0DW(2^w4pEXH<P]-mVA&5
    4+b{0$DN"[L2fz.MK>y~u Vh<;w!3|
1.請用已學過的知識編寫程序,找出小甲魚藏在下邊這個長字符串中的密碼,密碼的埋藏點符合以下規律:Y5d|MAp
Y5d|MAp
    a)每位密碼為單個小寫字母Powered by bbs.fishc.com
    b)每位密碼的左右兩邊均有且只有三個大寫字母qH{]*ZR
Suj|vEA'h<^1eF]7i*(tbZU+$H yx
(由於我們還沒有學習到文件讀取方法,大家下載後拷貝過去即可)9zk3R(q{
OtqD;C?r0kwco" R#A%BLTWFQ)
請下載字符串文件:  string2.zip (6.17 KB,下載次數: 18404)
    ~!_^:egm-)@EM.c{3Vs1]<4o=
      pjKAc^R#PaUNb)tB(x@Y;wG!
2.請寫下這一節課你學習到的內容:格式不限,回憶並複述是加強記憶的好方式!dXSmGQj^V
3QGLkM!Ulr"JP9{6w#Z0S7@
     v9Q+Ai[0EDpMTw kB`H?&gsKzXC
回复您的答案即可查看參考答案! ]dpLGyK3
!jTVsH?* JW5RteNCYy.xh Z~9dS
      !B<O%9cb|T_A.RUa@#~v+D?JeEr
測試題答案:Powered by bbs.fishc.com
      CE(JT[pkMc1<%=jyK{*q$P+ &9V

本帖隱藏的內容

版權屬於:bbs.fishc.com
0.如果希望在函數中修改全局變量的值,應該使用什麼關鍵字?$?blo,}
%}#Cgh<'kq|:u83wU1YG`
global關鍵字來自:bbs.fishc.com
v|MC#qQo%9lB=Pw@0[.ij$6)A{?e"c
舉個例子:Powered by bbs.fishc.com
  1. >>> count = 5
  2. >>> def MyFun():
  3.                 global count
  4.                 count = 10
  5.                 print(count)

  6. >>> MyFun()
  7. 10
  8. >>> count
  9. 10
複製代碼

j7&z629dnemWN1:!lV4Z
1.在嵌套的函數中,如果希望在內部函數修改外部函數的局部變量,應該使用什麼關鍵字?$w3EF~l
#-+_~%]KSrwDU`m'@={>TH
nonlocal關鍵字Powered by bbs.fishc.com
e0@bo9g^F%v]"7id[}I,AwL2ux
舉個例子:
  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
複製代碼

kS@bFq5uOj$J"0D.263^B
2. Python的函數可以嵌套,但要注意訪問的作用域問題哦,請問以下代碼存在什麼問題呢?
  1. def outside():
  2.     print('I am outside!')
  3.     def inside():
  4.         print('I am inside!')

  5. inside()
複製代碼

使用嵌套函數要注意一點就是作用域問題,inside()函數是內嵌在outside()函數中的,所以inside()是人妻,除了身為老公的outside()可以碰(調用),在外邊或者別的函數體裡是無法對其進行調用的。;c:!IfP
]AKt*wzxZsr-b+[$}IhG&omRD.W7
正確的調用應該是:
  1. def outside():
  2.     print('I am outside!')
  3.     def inside():
  4.         print('I am inside!')
  5.         
  6.     inside()
  7. outside()
複製代碼

[uq;TP1z'<mndQXY"o_|2B#3*sHj8
3.請問為什麼代碼A沒有報錯,但代碼B卻報錯了?應該如何修改?+9{zP*
pIm,AQ%l[yLT;6" |g?j}*@#Y1S7
代碼A:來自:bbs.fishc.com
  1. def outside():
  2.     var = 5
  3.     def inside():
  4.         var = 3
  5.         print(var)
  6.         
  7.     inside()

  8. outside()
複製代碼

代碼B:Powered by bbs.fishc.com
  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,說的是變量var沒有被定義就拿來使用,肯定錯啦!4ZW[J
M>D+afmER#J<c_]6NCb?9~
這裡outside()函數里有一個var變量,但要注意的是,內嵌函數inside()也有一個同名的變量,Python為了保護變量的作用域,故將outside()的var變量屏蔽起來,因此此時是無法訪問到外層的var變量的。%dFU6B*}
l@'x6yP3d8Kw9zZ; m4Wu*nJcreH
應該修改為:版權屬於:bbs.fishc.com
  1. def outside():
  2.     var = 5
  3.     def inside():
  4.         nonlocal var
  5.         print(var)
  6.         var = 8
  7.         
  8.     inside()
  9. outside()
複製代碼

=>~tE8VSf!,x&JrlAmz$WBv[y
4.請問如何訪問funIn()呢?e`BPGHp
  1. def funOut():
  2.     def funIn():
  3.         print('賓果!你成功訪問到我啦!')
  4.     return funIn()
複製代碼

只需要直接調用funOut() 即可:
  1. funOut()
  2. 賓果!你成功訪問到我啦!
複製代碼

WLokUB]@_%J$y)9?HmpaA*;0+4
5.請問如何訪問funIn()呢?C^&8=2 s
  1. def funOut():
  2.     def funIn():
  3.         print('賓果!你成功訪問到我啦!')
  4.     return funIn
複製代碼

區別於上一題,這裡你就需要用funOut()()訪問啦:S6yB8iWQ
  1. funOut()()
  2. 賓果!你成功訪問到我啦!
複製代碼

當然你也可以“曲線救國”:來自:bbs.fishc.com
  1. go = funOut()
  2. go()
  3. 賓果!你成功訪問到我啦!
複製代碼

$TQLwl1a^@]G jue!`[Dfd*z~pY23K
6.以下是“閉包”的一個例子,請你目測下會打印什麼內容?%c-7?'@ym*
  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())
複製代碼

會打印:版權屬於:bbs.fishc.com
  1. 6
  2. 7
  3. 8
複製代碼

有些魚油可能會比較疑惑,這……怎麼跟全局變量一樣了?局部變量x不是應該在每次調用的時候都重新初始化了嗎?Y|Mg($7
jUYh3[lD,nTQy@^}R>4_kxF;
其實大家仔細看看就明白了,當a = funX()的時候,只要a變量沒有被重新賦值,funX()就沒有被釋放,也就是說局部變量x就沒有被重新初始化。]VL%EdDnXj
b:{Q-z7Y$}TX'Ig,l^8 B"=%GN4v#
所以當全局變量不適用的時候,可以考慮使用閉包更穩定和安全,你還可以參考-> 遊戲中的角色移動:閉包在實際開發中的作用U~{"BC(E!
^]5Kg$"CqON1Q=Tzr;|f .`{

Powered by bbs.fishc.com
    Sz)(kXU"]$2tIEx_.?~AH8
          ht(_,$!-abOed46A&?K]lw#
動動手答案:版權屬於:bbs.fishc.com
    F'ANq?yL< Q,"7E@2JnM[o)>TZ

本帖隱藏的內容

版權屬於:bbs.fishc.com
0.請用已學過的知識編寫程序,統計下邊這個長字符串中各個字符出現的次數並找到小甲魚送給大家的一句話。m=80gecvpu
  1. str1 = '''拷貝過來的字符串'''
  2. list1 = []

  3. for each in str1:
  4.     if each not in list1:
  5.         if each == '\n':
  6.             print('\\n', str1.count(each))
  7.         else:
  8.             print(each, str1.count(each))
  9.         list1.append(each)
複製代碼

gs( {x_4.[mU=;M?rFO"|5
1.請用已學過的知識編寫程序,找出小甲魚藏在下邊這個長字符串中的密碼,密碼的埋藏點符合以下規律:i=>|3KYD
i=>|3KYD
    a)每位密碼為單個小寫字母Powered by bbs.fishc.com
    b)每位密碼的左右兩邊均有且只有三個大寫字母j~:y
3u=9m7_0 Pzy "pCV#RdwA,21^[t
  1. str1 = '''ABSaDKSbRIHcRHGcdDIF'''

  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.     """
  10.     |如果str1[i]是大寫字母:
  11.     |-- 如果已經出現小寫字母:
  12.     |-- -- 統計後邊的大寫字母
  13.     |-- 如果未出現小寫字母:
  14.     |-- -- 清空後邊大寫字母的統計
  15.     |-- -- 統計前邊的大寫字母
  16.     """
  17.     if str1[i].isupper():
  18.         if countB:
  19.             countC += 1
  20.         else:
  21.             countC = 0
  22.             countA += 1

  23.     """
  24.     |如果str1[i]是小寫字母:
  25.     |-- 如果小寫字母前邊不是三個大寫字母(不符合條件):
  26.     |-- -- 清空所有記錄,重新統計
  27.     |-- 如果小寫字母前邊是三個大寫字母(符合條件):
  28.     |-- -- 如果已經存在小寫字母:
  29.     |-- -- -- 清空所有記錄,重新統計(出現兩個小寫字母)
  30.     |-- -- 如果該小寫字母是唯一的:
  31.     |-- -- -- countB記錄出現小寫字母,準備開始統計countC
  32.     """
  33.     if str1[i].islower():
  34.         if countA != 3:
  35.             countA = 0
  36.             countB = 0
  37.             countC = 0
  38.         else:
  39.             if countB:
  40.                 countA = 0
  41.                 countB = 0
  42.                 countC = 0
  43.             else:
  44.                 countB = 1
  45.                 countC = 0
  46.                 target = i

  47.     """
  48.     |如果前邊和後邊都是三個大寫字母:
  49.     |-- 如果後邊第四個字母也是大寫字母(不符合條件):
  50.     |-- -- 清空記錄B和C,重新統計
  51.     |-- 如果後邊僅有三個大寫字母(符合所有條件):
  52.     |-- -- 打印結果,並清空所有記錄,進入下一輪統計
  53.     """
  54.     if countA == 3 and countC == 3:
  55.         if i+1 != length and str1[i+1].isupper():
  56.             countB = 0
  57.             countC = 0
  58.         else:
  59.             print(str1[target], end='')
  60.             countA = 3
  61.             countB = 0
  62.             countC = 0
複製代碼

Bsw3S|5Ml8j[Z@C4r;"+%gm7I(H{
2.請寫下這一節課你學習到的內容:格式不限,回憶並複述是加強記憶的好方式!'WA{c
X% i&me6c@" yTxk:Lh?zP|M
小甲魚希望你認真對待作業就像你希望小甲魚推出高質量視頻一樣渴望^_^ g@j7J&Q
    這節課主要講解內嵌函數和閉包
(1)glabal 關鍵字
將函數體內部的局部變量變為全局變量。
(2)內嵌函數(內部函數)
需要注意的是內嵌函數的整個作用域,都在外部函數之內的,也就是說,出了外部函數的範圍,是沒有辦法調用內部函數的。即:假設函數fun2()的定義和調用的過程都在函數fun1()內,那麼除了在fun1() 這個函數體裡面可以隨便調用fun2()外,出了fun1(),就沒有任何可以對fun2()調用的方式了。
(3)閉包
閉包是函數式編程重要的語法結構。不同的編程語言實現閉包的形式不同,Python中閉包從表現形式上定義為:如果在一個內部函數里,對外部作用域(但不是在全局作用域)的變量進行引用,那麼內部函數就被認為是閉包。例如:
對於函數FunX(),內部函數為FunY(),內部函數的外部作用域就是FunX()的整個函數空間,的變量就是x,對它進行引用了,達到這個要求了,所以就是內部函數FunY( )就是一個閉包。那如何進行調用呢?
首先我們發現調用FunX()會得到一個函數,i是函數FunX()的函數,如果需要得到x*y的值,我們還需要對FunY()進行調用。
使用閉包需要注意的是:因為閉包的概念是由內部函數演變而來,所以你也不能在外部函數的外邊對內部函數進行調用。在閉包中,外部函數的局部變量對內部函數的局部變量就相當於之前的全局變量之於局部變量的關係。在內部函數中,你只能對外部函數的局部變量進行訪問,但你不能對它進行修改。例如:
因為這裡的x *= x中的x被認為是一個局部變量,且沒有被定義,所以報錯。如果需要在局部使用全局的變量,需要用到nonlocal關鍵字,這個關鍵字的使用方法與global相同。

0 留言:

發佈留言