python中*args與**kwarsg及閉包和裝飾器的用法
*args與**kwarsg及閉包和裝飾器
過程
先理解閉包,再理解裝飾器,不要忘了不定長參數
def func(): msg = '111' def func1(): print(msg) return func1 """ 1-理解閉包 閉包即內部函數調用外部函數作用域里面的變量 比如func1就是一個閉包函數 """ func()()# 這里實際上是func1()
""" 2-裝飾器 fn是被裝飾的目標函數 2.1-僅僅只是傳遞函數名的裝飾器[基本不會用到] 2.2-裝飾帶有參數的函數 2.3-裝飾帶有返回值的函數 2.4-裝飾參數不確定的函數[可歸類到裝飾帶有參數的函數里面] 2.5-裝飾器本身攜帶參數 """
def decorator(fn): def wrapper(): print("添加的功能,裝飾不帶有參數的函數") return fn() return wrapper @decorator def test(): print("原有功能") test()# 實際上是decorator(test) def decorator1(fn): def wrapper(n1,n2): print("添加的功能,裝飾帶有參數的函數") return fn(n1,n2) return wrapper @decorator1 def test1(a,b): print("a+b=%s"%(a+b)) print("原有功能") test1(1,2)# 實際上是decorator1(test1(1,2)) def decoretor2(fn): def wrapper(): print("添加的功能,裝飾帶有返回值的函數") res = fn() return res return wrapper @decoretor2 def test2(): print("原有功能") return "返回值001" a = test2() # 實際是decorator2(test2) print(a) def decorator3(fn): def warpper(*args,**kwargs): print("添加的功能,裝飾不定長參數的函數") return fn(*args,**kwargs) return warpper @decorator3 def test3(n1,n2,n3): print("原有功能") print(n1+n2+n3) test3(1,2,3)# 實際上是decorator1(test1(1,2,3)) def decorator4(home): def func_1(fn): def wrapper(*args,**kwargs): print("裝飾器本身攜帶參數") print("目前家在%s"%(home)) return fn(*args,**kwargs) return wrapper return func_1 @decorator4(home='wuhan') def test4(n1,n2,n3): print("原有功能") print(n1+n2+n3) # test3(1,2,3)=decorator3(home="武漢")(test(1,2,3))() """ 1-先調用decorator3(home="wuhan") 2-執(zhí)行func_1(test(1,2,3)) # 到這里其實就和前面的裝飾器一樣 3-執(zhí)行wrapper 4-執(zhí)行test(1,2,3) """ test4(1,2,3)
Python fun(*args,**kwargs)中*args,**kwargs參數含義及用法
1. Python函數中的兩種參數
我們知道,在Python中有兩種參數
- 位置參數(positional argument): 位置參數只能由參數位置決定
- 關鍵詞參數(keyword argument): 關鍵詞參數只需要用 keyword = somekey 的方法即可傳參
位置參數只能由參數位置決定。這也就決定了位置參數一定要在前面,否則關鍵詞參數數量的變化都會使得位置無法判斷。
2. 理解函數調用中的*
*的作用是將tuple或者list中的元素進行unpack,分開傳入,作為多個參數。
def func(a,b,c) ?? ?print(a,b,c) alist = [1,2,3] # 這里alist的長度必須和函數中參數的個數相同,否則會報錯 func(*alist) ?? ?# 等同于 func(1, 2, 3) 1 2 3
2.1 * 做了什么
它拆開數列alist的數值作為位置參數,并把這些位置參數傳給函數func來調用。
因此拆數列、傳位置參數意味著func(*alist)與func(1,2,3)是等效的,因為 alist= [1,2,3]。
3. 理解函數調用中的**
**的作用是unpack字典,并將字典中的數據項作為鍵值參數傳給函數。
為了更好的理解舉幾個例子:
def func(a, b, c): ? ? print(a, b, c) ? ?? if __name__ == "__main__": ? ? dic = {'b': 2, 'c': 3} ? ? func(1, b=2, c=3) ? ? func(1, **dic) 1 2 3 1 2 3
4. 理解函數調用中的*args和**kwargs
kwargs是keyword argument的縮寫,args就是argument。常見的是*args 在 **kwargs 前面。
這兩個的用途和效果如下:
def this_fun(a,b,*args,**kwargs): ?? ?""" ?? ?在這個函數定義中,參數”a, b”代表”常規(guī)參數列表”。 ?? ?args 接收元組作為位置參數,而非是常見的參數列表 ?? ? ?? ?""" ? ? print(a,b) ? ? print(args) ? ? print(kwargs) if __name__ = '__main__' ?? ?this_fun(0,1,2,3,index1=11,index2=22) ?? ? 0,1 (2, 3) {'index2': 22, 'index1': 11}
也就是說,第一中不定的參數形式把剩下的沒有關鍵字的參數收起來形成一個tuple,而第二種把有關鍵字的收起來做成一個字典。
5. 實例說明args, kwargs的應用場景
5.1 子類傳參給父類方法
在任何時候繼承類和重寫方法的,我們應當用到args, kwargs將接收到的位置參數和鍵值參數給父類方法。通過實例我們更好的理解
class Model(object): ? ? def __init__(self, name): ? ? ? ? self.name = name ? ? def save(self, force_update=False, force_insert=False): ? ? ? ? if force_update and force_insert: ? ? ? ? ? ? raise ValueError("Cannot perform both operations") ? ? ? ? if force_update: ? ? ? ? ? ? print("Updated an existing record") ? ? ? ? if force_insert: ? ? ? ? ? ? print("Created a new record")
定義一個類,我們可以創(chuàng)建類的對象,類的對象有一個方法save().假設類的對象可以通過save()方法保存到數據庫中。通過函數save()參數來決定是否在數據庫中創(chuàng)建一條記錄或者更新現存的記錄。
構造一個新類,類有Model的行為,但只有符合某些條件才會保存這個類的對象。這個新類繼承Model,重寫Model的save()
class ChildModel(Model): ? ? def save(self, *args, **kwargs): ? ? ? ? if self.name == 'abcd': ? ? ? ? ? ? super(ChildModel, self).save(*args, **kwargs) ? ? ? ? else: ? ? ? ? ? ? return None
實際上對應的保存動作發(fā)生在’Model’的save方法中。所以我們調用子類的的save()方法而非’Model’的方法.子類ChildModel的save()接收任何父類save()需要的參數,并傳給父類方法。因此,子類save()方法參數列表中有*args和**kwargs,它們可以接收任意位置參數或鍵值參數,常規(guī)參數列表除外。
下面創(chuàng)建ChildModel實體并調用save方法:
c=ChildModel('abcd') c.save(force_insert=True) c.save(force_update=True) # 結果 Created a new record Updated an existing record
這里傳參數給對象的save()方法。調用的是子類的save(), 它接收一個包含關鍵字參數kwargs的字典。然后,它使用**將字典作為關鍵字參數unpack,然后將其傳遞給超類save()。因此,超類save()獲得關鍵字參數force_insert并執(zhí)行相應的操作。
5.2 *args 實現sum
def my_sum(*args): ?? ?res = 0 ?? ?for val in args: ?? ??? ?res += val ?? ?return res ?? ? l1 = [4, 8] l2 = [1,2,3] print(my_sum(*l1)) ?? ??? ?# 12 print(my_sum(*l2)) ?? ??? ?# 6 print(my_sum(4,5,6)) ?? ?# 15
以上為個人經驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關文章
Python使用random和tertools模塊解一些經典概率問題
這篇文章主要介紹了Python使用random和tertools模塊解一些經典概率問題,本文講解了使用random和tertools模塊解羊車門問題、撲克牌問題、生日悖論等經典概率問題,需要的朋友可以參考下2015-01-01