python學習手冊17作用域

天飛.h發表於2016-02-23

點選(此處)摺疊或開啟

  1. #!/usr/bin/env python
  2. #* coding:utf8 *
  3. #python對變數的操作都是在名稱空間中(作用域),變數名被賦值的位置決定了這個變數名能被訪問到的範圍。
  4. #變數賦值的地方決定了名稱空間,即語義作用域。
  5. #一個函式所有變數名都與函式的名稱空間相關。
  6. `
  7. def內定義的變數名只能在def內使用。
  8. def內外的變數名不衝突。
  9. 變數對應的作用域: 作用於可以防止程式變數名衝突。
  10.     def內賦值就是def內。
  11.     巢狀def,對於巢狀函式是非本地。
  12.     def外賦值,是全域性的。
  13. `
  14. X=99#全域性變數
  15. def func():
  16.     X=88 #函式本地變數
  17. #函式定義了本地作用哉,模組定義了全域性作用域。
  18. `
  19. 內嵌的模組是全域性作用域。
  20. 全域性作用域的範圍僅限單個檔案。(全域性是相對一個模組或檔案而言。)
  21. 每次對函式的呼叫都建立了一個新的本地作用域。
  22. 賦值的變數名除非宣告為全域性變數或本地變數,否則均為本地變數。
  23. 所有其它的變數名都可以歸納為本地、全域性、或都內建的。
  24. 此外,原處改變物件並不會把變數劃分為本地變數,只有對變數名賦值才可以。即修改一個物件並不是對一個名稱賦值。
  25. `
  26. print(`變數名解析:LEGB原則`)
  27. `
  28. 變數名按:本地(L)->上層函式(E)->全域性(G)->內建(B)的順序查詢
  29. 預設變數名賦值會建立或改變本地變數。(賦值總是建立或改變變數名,除非宣告過型別。)
  30. 全域性宣告與非本地宣告將賦值變數名對映到模組內部的作用域。
  31. `
  32. #全域性變數
  33. X=99 #X與func在本模組中是:全域性變數
  34. def func(Y): #Y與Z在函式中是本地變數
  35.     #本地變數
  36.     Z=X+Y #X是全域性變數
  37.     return Z
  38. print(func(1))
  39. #內建作用域 __builtin__ 內建模組
  40. #import __builtin__
  41. #print(dir(__builtin__))
  42. #global語句
  43. `
  44. 全域性變數是位於模組檔案內部頂層的變數
  45. 全域性變數在函式內必須經過宣告
  46. 全域性變數在函式內不用宣告可以引用
  47. `
  48. X=88 #全域性變數
  49. def func():
  50.     global X #全域性變數宣告
  51.     X=99
  52.     return X
  53. print(func())
  54. print(X)
  55. a,b=1,2
  56. def all_global():
  57.     global x
  58.     x=a+b
  59.     print(x)
  60. all_global()
  61. print(x)
  62. #最小化全域性變數
  63. #原因是:流程控制比較難,儲存狀態資訊過於複雜。
  64. #最小化檔案間的修改
  65. #隱性的跨檔案依賴性,在最好的情況下會導致程式碼不靈活,最壞的情況會引發bug。
  66. import t17mod
  67. t17mod.test()
  68. #這個例子表明全域性變數與模組的屬性是等效的。但比global要多寫許多語句。
  69. `
  70. 作用域和巢狀函式
  71. `
  72. #按照LEGB法測,如果巢狀函式將一個變數宣告為全域性變數,它將改變整個模組作用域。如果我們只想想必被巢狀函式同為此變數名的變數的作用域,可以使用nonlocal宣告,賦值會修改最近的巢狀函式中的變數的作用域
  73. print(`作用域和巢狀函式`)
  74. TT=99 #全域性作用
  75. def f1():
  76.     TT=88 #本地作用
  77.     def f2(): #f2是f1函式的本地變數
  78.         print(TT) #根據LEGB法則,X=88
  79.     f2()
  80. f1()
  81. #工廠函式,一個能記住巢狀作用域的變數值的函式,雖然有可能那個作用域已經不存在了。但類是最適合做記憶狀態的。
  82. #本地作用域中N被作為執行的狀態資訊保留下來。
  83. def maker(N):
  84.     def action(M):
  85.         return N*M
  86.     return action
  87. f = maker(5) #N=5
  88. print(f(2)) #M=2,N是被記憶的為5
  89. #新建立的函式不影響原來的
  90. g=maker(9)
  91. print(g(2))
  92. print(f(2))
  93. `
  94. 儘量避免在def中內巢狀def。只要第二個函式定義在第一個函式呼叫前就可行。
  95. 如此可以避免使用巢狀
  96. `
  97. def f1():
  98.     x=100
  99.     f2(x)
  100. def f2(x):
  101.     print(x)
  102. f1()
  103. `
  104. 巢狀作用域和lambda
  105.     lambda是一個表示式,但類似def,會生成新的作用域,可以使用在def不能使用的地方,如一個列表或是字典中
  106. `
  107. def func(N):
  108.     action=(lambda M : N ** M)
  109.     return action
  110. A=func(5)
  111. print(A(2))
  112. print(func(5)(3))
  113. `
  114. 作用域與帶有迴圈變數的預設引數相比較
  115.     lambda或def函式在一個函式中定義,巢狀在一個迴圈中,並引用了上層函式的一個變數,變數在迴圈中被改變,但lambda或def函式最後值是最後一次迴圈後的值,不會受其它迴圈值影響
  116. `
  117. def makeAction():
  118.     acts = []
  119.     for i in range(5):
  120.         acts.append(lambda n : i ** n )
  121.     return acts
  122. actss=makeAction()
  123. print(actss[2](2))
  124. #因此必須把巢狀函式的值傳遞給巢狀作用域的變數
  125. def makeAction2():
  126.     acts = []
  127.     for i in range(5):
  128.         acts.append(lambda n, i=i: i ** n)
  129.     return acts
  130. actsss=makeAction2()
  131. print(actsss[3](2))
  132. #actsss[i]i最大不能超過range(5)的最大值。
  133. print(actsss[4](2))
  134. `
  135. 作用域可以被任意巢狀,但是隻有內嵌的函式會被搜尋。
  136.     在python中,平坦優於巢狀。
  137. `
  138. `
  139. nonlocal允許對巢狀函式作用域中的名稱賦值,並且把這樣的名稱作用域查詢限制在巢狀def.
  140. `
  141. def tester(start):
  142.     state=start
  143.     def nester(label):
  144.         #預設不允許修改巢狀的def作用域中的名稱。
  145.         #state +=1 #UnboundLocalError: local variable `state` referenced before assignment
  146.         #python3.0中使用nonlocal修改,前提是nonlocal的變數在上層函式中已經賦值過。
  147.         #nonlocal只在上層函式的作用域中查詢變數,不會去其它作用域查詢。
  148.         #nonlocal state
  149.         #nonlocal nostate #SyntaxError: no binding for nonlocal `nostate` found
  150.         print(label,state)
  151.         #state +=50
  152.     return nester
  153. F=tester(100)
  154. F(111) #111 100
  155. F(112) #112 150
  156. #如果建立一個新的副本,不會影響原來的state
  157. G=tester(10)
  158. G(`egg`) #egg 10
  159. G(`egg2`) #egg2 60
  160. F(`old`) #old 200
  161. states2 = 9
  162. def tester2(start):
  163.     def nester2(lable):
  164.         global states2
  165.         states2 = 99
  166.         print(lable,states2)
  167.     return nester2
  168. H=tester2(1000)
  169. H(`new`) #new 99
  170. #nonlocal語句允許在內在保持可變狀態的多個副本,並且解決了在類無法保證的情況下的簡單的狀態保持。
  171. #下面使用類實現存狀態保持。
  172. class ctest:
  173.     def __init__(self,A):
  174.         self.state = A
  175.     def funcA(self,label):
  176.         print(label,self.state)
  177.         self.state +=1
  178. CL=ctest(88)
  179. CL.funcA(`egg`) #(`egg`, 88)
  180. CL.funcA(`egg2`) #(`egg2`, 89)
  181. print(CL.state) #90
  182. #使用__call__運算子過載工具獲取一個例項上的直接呼叫
  183. class ct:
  184.     def __init__(self,A):
  185.         self.state = A
  186.     def __call__(self,label):
  187.         print(label,self.state)
  188.         self.state +=11
  189. CL1=ct(77)
  190. CL1(`python`) #(`python`, 77)
  191. CL1(`ADD11`) #(`ADD11`, 88)
  192. #下面這個沒搞通,再研究了。
  193. `
  194. def Z(start):
  195.     def Y(lable):
  196.     print(lable,Y.state)
  197.     Y.state += 1
  198.     Y.state = start
  199.     return Y
  200. X=Z(188)
  201. X(`egg`)
  202. `
  203. `
  204. 全域性、非本地、類、函式屬性都提供了狀態保持選項。
  205. 全域性只支援共享資料,類要用OOP知識,類和函式屬性都允許巢狀自身之外訪問狀態。最好的工具取決於程式的目的。
  206. `

t17mod.py

點選(此處)摺疊或開啟

  1. #!/usr/bin/env python
  2. #coding:utf8
  3. var=99 #全域性變數=模組屬性
  4. def local():
  5.     var = 0 #本地變數,不影響
  6. def glob1():
  7.     global var #全域性變數
  8.     var +=1 #修改全域性var=100
  9. def glob2():
  10.     var =0
  11.     import t17mod #匯入模組,變成模組屬性
  12.     t17mod.var +=1
  13. def glob3():
  14.     var = 0
  15.     import sys
  16.     glob = sys.modules[`t17mod`] #對模組屬性生新賦值
  17.     glob.var +=1
  18. def test():
  19.     print(var)
  20.     local();glob1();glob2();glob3() #按照執行順序,第一個函式不影響全域性變數
  21.     print(var)

結果

點選(此處)摺疊或開啟

  1. /usr/bin/python2.7 /home/talen/PycharmProjects/untitled/t17.py
  2. 變數名解析:LEGB原則
  3. 100
  4. 99
  5. 99
  6. 3
  7. 3
  8. 99
  9. 102
  10. 作用域和巢狀函式
  11. 88
  12. 10
  13. 18
  14. 10
  15. 100
  16. 25
  17. 125
  18. 16
  19. 9
  20. 16
  21. (111, 100)
  22. (112, 100)
  23. (`egg`, 10)
  24. (`egg2`, 10)
  25. (`old`, 100)
  26. (`new`, 99)
  27. (`egg`, 88)
  28. (`egg2`, 89)
  29. 90
  30. (`python`, 77)
  31. (`ADD11`, 88)
  32. Process finished with exit code 0


相關文章