程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式師世界 >> 編程語言 >  >> 更多編程語言 >> Python

今日提升——Python之Python之global、nonlocal關鍵字以及閉包和裝飾器

編輯:Python

今天又把《流暢的Python》翻了一遍,更進一步的理解了Python的global、nonlocal關鍵字以及閉包和裝飾器。

global關鍵字:

針對定義在python的全局變量,與之相對的是局部變量(一般定義在函數中),全局變量和局部變量的一個主要區別是 :

在函數內部,全局變量只能被訪問,而不能直接被操作,如果想讓全局變量能緊隨函數操作而變化,則需要在函數內部使用global關鍵字,見下面例子

 例1:不直接操作全局變量,全局變量值不發生變化

outer = '全局變量'
def f1():
a = outer + 'ok'
print(a)
f1()
print(outer)

 輸出 :
 

全局變量ok
全局變量

例2 :直接在函數內部操作全局變量,導致報錯

outer = '全局變量'
def f2():
outer = outer + 'ok'
print(outer)
f2()
print(outer)

輸出 :

UnboundLocalError: local variable 'outer' referenced before assignment

例子3 :函數內部可以直接操作全局變量,並且使得全局變量在函數調用緊跟變化(這裡我調用兩次,讓結果呈現明顯)

def f3():
global outer
outer = outer + 'ok'
print(outer)
f3()
print(outer)
f3()
print(outer)

輸出 :

全局變量ok
全局變量ok
全局變量okok
全局變量okok

nonlocal關鍵字:

如果我在定義函數時,在函數內部又定義了一個函數,像下面這樣,

​
def outer():
outerNum = 10
def inner():
pass
​

如果我想在內部函數裡面調用外部函數的outerNum,並且讓外部outerNum跟隨內部函數調用變化而變化,那就需要nonlocal關鍵字,下面再看幾個和上面global類似的例子便於理解

 例1 :這裡我沒有使用nonlocal,所以outerNum不隨內部調用而變化

def outer():
outerNum = 10
def inner():
innerNum = outerNum + 10
print(innerNum)
inner()
print(outerNum)
outer()

輸出 : 

20
10

例2:這裡由於沒有使用nonlocal關鍵字就在內部函數對outerNum進行操作,導致報錯

def outer():
outerNum = 10
def inner():
outerNum = outerNum + 10
print(outerNum)
inner()
print(outerNum)
outer()

輸出 : 

UnboundLocalError: local variable 'outerNum' referenced before assignment

例3 : 在內部函數使用nonlocal調用外函數變量,外部函數變量內部函數調用而變化(這裡多調用幾次為了更加明顯)

def outer():
outerNum = 10
def inner():
nonlocal outerNum
outerNum = outerNum + 10
print(outerNum)
inner()
print(outerNum)
inner()
print(outerNum)
inner()
print(outerNum)
outer()

輸出 :

20
20
30
30
40
40

閉包 :

閉包,說白了,樣貌就是嵌套函數,只不過外部函數只能調用內部函數,而內部函數可以調用外部函數的變量(這時候,上述的nonlocal關鍵字就起到了作用),我曾經看過一個Dart語言講師提到的 —— 閉包的優點:

1. 常駐內存                2. 不污染全局

看下面這個例子——一個根據持續添加數值求總體均值的函數 :

def averageNUM():
nums = []
def inner(anum):
nums.append(anum)
return sum(nums) / len(nums)
return inner
arg = averageNUM()
print(arg(1))
print(arg(2))
print(arg(3))

結果 :

1.0
1.5
2.0

由例子可以看出——由於值變成了常駐內存,從而在函數結束後不會釋放(但是這樣占用內存啊)。

這樣定義閉包的形式看起來很像匿名函數,但是匿名函數每次使用之後都會釋放內存(用完就扔)。

裝飾器 :

在介紹裝飾器之前先看兩個功能相同的函數 —— 都是求數字4的平方根的函數 : 

def useFunc(func):
return func(4)
def getSqrt(n):
return n ** .5
print(useFunc(getSqrt))
# 2.0
def useFunc(func):
return func(4)
@useFunc
def getSqrt(n):
return n ** .5
print(getSqrt)
# 2.0

  方案二即一個簡單的裝飾器 —— 根據方案一就可以大致理解,函數的參數是函數時,可以選擇裝飾器,如果只是一個函數當參數,一個主函數是看不出什麼的;如果對多個函數掉同一個裝飾器,就能體現裝飾器的神奇功能——拓展額外功能、統一便於管理

def useFunc(func):
print('額外功能')
return func(4)
@useFunc
def getSqrt(n):
return n ** .5
@useFunc
def anotherFunc1(n):
return n ** 2
@useFunc
def anotherFunc2(n):
return n * 2
print(getSqrt)
print(anotherFunc1)
print(anotherFunc2)

輸出 : 

額外功能
額外功能
額外功能
2.0
16
8

OK, 差不多就是我今天的收獲了,bye……


  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式師世界 All Rights Reserved