Python基礎--函數進階與裝飾器

來源:互聯網
上載者:User

標籤:python   函數   裝飾器   

函數範圍
python函數啟動並執行時候,會建立自己的scope,即範圍(或者說函數有自己的namespace,即命名空間)。執行函數時,如果在函數體中遇到了變數名,python首先會在該函數的namespace內尋找該變數。如果找不到就會跳出函數在全域找(如果是嵌套函數就會找上一級函數,依次往上找,然後是在內建中找,在找不到就會報錯)。

首先定義一個簡單的函數
def test():
a = 1
print(1)

test()

如果在外面列印a會怎樣那?

效果

說明a的範圍存在於函數內
如果在外面定義一個a 函數內部是可以使用的

在函數內部可以修改a的值,但是無法改變外面的值

其實函數沒有改變外面的值,只是在函數內部重新建立了一個和外部變數一樣的值
把地址列印出來可以證明
a = 1
def test():
a = 2
print(a)
print(id(a))
test()
print(a)
print(id(a))

地址是不同的

如果在函數內使用的外部變數,那麼就是直接使用的外部變數(不會建立新的變數)

全域變數是在整個py檔案中聲明,全域範圍內都可以訪問
局部變數是在某個函數中聲明的,只能在該函數中調用它,如果試圖在超出範圍的地方調用,就會報錯。
函數可以調用全域變數,(就是直接使用的全域變數)
如果局部變數和全域變數一樣,那麼可以在函數內部對全域變數修改,(僅限於函數內部,對外部不起作用),這種情況其實是在內部重新建立的臨時變數只不過和全域變數一樣,本質上沒有對全域變數產生任何影響。

函數基礎可以參考
http://blog.51cto.com/linuxubuntu/2085265
函數的範圍也叫局部範圍,它的範圍是整個函數,出了函數不起作用

範圍鏈
name = "Jack"
def f1():
name = "Mike"
def f2():
name = "Tom"
print(name)
f2()
print(name)
f1()
print(name)
#執行過程為:調用f1()函數,定義name 和 f2()函數,
#執行f2()函數,列印f2()中的name
#然後列印f1()中的name,最後列印全域變數的name

Python中有範圍鏈,
變數會由內到外找,先去自己範圍去找,
自己沒有再去上級去找,直到找不到報錯
例如:
把內部變數去掉後
name = "Jack"
def f1():
#name = "Mike"
def f2():
#name = "Tom"
print(name)
f2()
print(name)
f1()
print(name)

列印地址

可以看出全部是全域變數的地址
類似
def f1():
name = "Jack"
def f2():
print(name)
f2()
f1()
叫做嵌套函數,就是一個函數裡面有一個或多個函數
函數可以使用外部變數但是無法修改外部變數,外部變數也無法修改函數內部的變數。
如果想在外部對函數內部的資料修改要怎麼做,可以在內部返回函數地址,進行修改
函數內部的函數在修改完資料後直接返回地址,這樣記憶體中的資料不會被回收,達到在外部調用修改的目的

正常是這樣
def f1():
b = 1
def f2(b):
b += 1
print(b)
f2(b)
f1()
f1()
f1()
f1()
f1()


對代碼修改後:
def f1():
def f2(b):
b += 1
return b
return f2
print(f1())
print(f1()(1))


可以看到調用f1()得到的是一個函數地址
可以把f1()賦值給一個變數,然後執行
這就是簡單的閉包
閉包就是你調用了一個函數A,這個函數A返回了一個函數B給你。這個返回的函數B就叫做閉包。你在調用函數A的時候傳遞的參數就是自由變數。
這裡面調用f1的時候就產生了一個閉包——f2,並且該閉包持有自由變數——b,因此這也意味著,當函數f1的生命週期結束之後,b這個變數依然存在,因為它被閉包引用了,所以不會被回收。

裝飾器

裝飾器本質上是一個Python函數,就是在不改變原來函數的情況下新增功能。
例如:
冬天為了禦寒穿上棉衣(基本需求),為了加強保暖效果可以帶上帽子防風眼鏡手套等配置(新增需求)
#給下面函數加一項輸入的功能
def f1():
print(‘f1‘)
def f2():
print(‘f2‘)
def f3():
print(‘f3‘)
第一種方式:
每個函數裡加入同樣的代碼,效率太差
第二種方式:
將新功能封裝成函數在每個函數下調用,效率提高了,但是違反開放封閉原則
開放封閉原則,其核心的思想是:
軟體實體應該是可擴充,而不可修改的。也就是說,對擴充是開放的,而對修改是封閉的。
因此,開放封閉原則主要體現在兩個方面:
對擴充開放,意味著有新的需求或變化時,可以對現有代碼進行擴充,以適應新的情況。
對修改封閉,意味著類一旦設計完成,就可以獨立完成其工作,而不要對類進行任何修改。
簡單的說就是
封閉:已實現的功能代碼塊不做修改
開放:對現有代碼進行擴充
在python 中一切皆對象,所以在Python中,函數本身也是對象,在全域域,函數對象被函數名引用著,因此,完全可以用其他變數名引用這個函數對象,相當於改個名字。
比如:
def test():
print("test")
調用時可以直接調用
test()
也可fu=test
fun()
這樣調用

def test():
print("test")
fu = test
fu()

既然函數名可以賦值給變數,那麼可不可以把賦值過得變數當做參數傳遞給函數那,答案是可以的

把代碼改一下
def msg(fun):
fun()
inputword = input("請輸入資訊:")
print("輸出資訊為:",inputword)

def f1():
print(‘f1‘)

msg(f1)


調用後正常輸出f1函數的功能

這樣功能可以加上了,不過改變了調用方式
上面調用的是f1()這裡改為msg(f1),
既然把函數賦值給變數可以加個括弧可以運行,那麼能不能把msg的地址重新賦值給變數那?通過上面的閉包我們可以知道是可以的

把代碼改一下
def msg(fun):
def func():
fun()
inputword = input("請輸入資訊:")
print("輸出資訊為:",inputword)
return func

def f1():
print(‘f1‘)

f1 = msg(f1)
f1()#這樣調用後就可以正常執行,其實這裡執行的是func函數



這樣就實現的功能並且不用改變調用方式

這樣就實現了裝飾器,不過在python中用文法糖@來實現實現方式為:
def msg(fun):#在調用f1時執行過程為 msg(fun)相當於msg(f1) fun相當於f1
def func():
fun()
inputword = input("請輸入資訊:")
print("輸出資訊為:",inputword)
return funcbr/>@msg
print(‘f1‘)

#f1 = msg(f1)

f1()#這樣調用後就可以正常執行,其實這裡執行的是func函數

列印出地址

可以看出func的地址和f1的地址一樣

如果被裝飾的函數有參數怎麼辦那?那就在裡面的函數加上參數
def msg(fun):
def func(arg):
fun(arg)
inputword = input("請輸入資訊:")
print("輸出資訊為:",inputword)
return funcbr/>@msg
print(arg)
f1(‘hello world‘)


如果是多個參數就要用到*args and **kwargs

def dec(fun):
def warpper(*args, *kwargs):
fun(
args, **kwargs)
print("通用裝飾器案例")
return warpperbr/>@dec
print(arg1,arg2)
f1([1,2,3],{‘a‘:"A",‘b‘:"b"})

Python基礎--函數進階與裝飾器

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.