python 装饰器简单笔记(附 *args **kw)
1. 裝飾器
由于函數也是一個對象,而且函數對象可以被賦值給變量,所以,通過變量也能調用該函數。
現在,假設我們要增強函數的功能,比如,在函數調用前后自動打印日志,但又不希望修改函數的定義,這種在代碼運行期間動態增加功能的方式,稱之為“裝飾器”(Decorator)。
本質上,decorator就是一個返回函數的高階函數。
# 這里定義一個能打印日志的decorator,所以接受一個函數作為參數,并返回一個函數 def log1(func):def wrapper(*args, **kw): # (*args, **kw),因此,wrapper()函數可以接受任意參數的調用print('call %s():' % func.__name__)return func(*args, **kw)return wrapper # @log相當于執行:now = log(now) @log1 # 調用now()函數,不僅會運行now()函數本身,還會在運行now()函數前打印一行日志 def now1():print('2018-3-25')f = now1 f() # __name__已經從原來的'now'變成了'wrapper' print now1.__name__ print f.__name__ print '--------------------------------------------------------' # 如果decorator本身需要傳入參數 def log2(text):def decorator(func):def wrapper(*args, **kw):print('%s %s():' % (text, func.__name__))return func(*args, **kw)return wrapperreturn decorator# 相當于執行:now = log('execute')(now) @log2('execute') def now2():print('2018-3-25')f = now2 f() print now2.__name__ print f.__name__print '--------------------------------------------------------' import functoolsdef log3(text):def decorator(func):# 把原始函數的__name__等屬性復制到wrapper()函數中,Python內置的functools.wraps@functools.wraps(func)def wrapper(*args, **kw):print('%s %s():' % (text, func.__name__))return func(*args, **kw)return wrapperreturn decorator@log3('execute') def now3():print('2018-3-25')f = now3 f() print now3.__name__ print f.__name__運行結果:
call now1(): 2018-3-25 wrapper wrapper -------------------------------------------------------- execute now2(): 2018-3-25 wrapper wrapper -------------------------------------------------------- execute now3(): 2018-3-25 now3 now32. 函數的參數
這里最好使用python 3 版本的解釋器。
2.1 可變參數
這里只給出簡單的例子:
def calc(numbers):sum = 0for n in numbers:sum = sum + n * nreturn sum# 調用的時候需要先組裝出一個list或tuple print calc([1, 2, 3]) print calc((1, 3, 5, 7))# 把函數的參數改為可變參數 def calc(*numbers):# 在函數內部,參數numbers接收到的是一個tuple#print 'numbers:',numbers sum = 0for n in numbers:sum = sum + n * nreturn sum# 調用函數的方式可以簡化成這樣 print calc(1, 2, 3) print calc(1, 3, 5, 7)# 如果已經有一個list或者tuple,一種麻煩的方式 nums = [1, 2, 3] print calc(nums[0], nums[1], nums[2]) # 用可變參數的方式:list的所有元素作為可變參數傳進去 print calc(*nums)運行結果:
14 84 numbers: (1, 2, 3) 14 numbers: (1, 3, 5, 7) 84 numbers: (1, 2, 3) 14 numbers: (1, 2, 3) 142.2 關鍵字參數
可變參數允許你傳入0個或任意個參數,這些可變參數在函數調用時自動組裝為一個tuple。而關鍵字參數允許你傳入0個或任意個含參數名的參數,這些關鍵字參數在函數內部自動組裝為一個dict。
同樣只給出程序:
# 注意kw獲得的dict是extra的一份拷貝,對kw的改動不會影響到函數外的extra def person(name, age, **kw):print('name:', name, 'age:', age, 'other:', kw)person('Michael', 30) person('Bob', 35, city='Beijing') person('Adam', 45, gender='M', job='Engineer')# 和可變參數類似,也可以先組裝出一個dict,然后,把該dict轉換為關鍵字參數傳進去 extra = {'city': 'Beijing', 'job': 'Engineer'} person('Jack', 24, city=extra['city'], job=extra['job'])# 簡化的調用 extra = {'city': 'Beijing', 'job': 'Engineer'} person('Jack', 24, **extra)運行結果:
('name:', 'Michael', 'age:', 30, 'other:', {}) ('name:', 'Bob', 'age:', 35, 'other:', {'city': 'Beijing'}) ('name:', 'Adam', 'age:', 45, 'other:', {'gender': 'M', 'job': 'Engineer'}) ('name:', 'Jack', 'age:', 24, 'other:', {'city': 'Beijing', 'job': 'Engineer'}) ('name:', 'Jack', 'age:', 24, 'other:', {'city': 'Beijing', 'job': 'Engineer'})2.3 命名關鍵字參數
對于關鍵字參數,函數的調用者可以傳入任意不受限制的關鍵字參數。至于到底傳入了哪些,就需要在函數內部通過參數檢查。
使用命名關鍵字參數時,要特別注意,如果沒有可變參數,就必須加一個*作為特殊分隔符。如果缺少*,Python解釋器將無法識別位置參數和命名關鍵字參數。
下面是基于python 3.5 版本
def person1(name, age, **kw):if 'city' in kw:# 有city參數passif 'job' in kw:# 有job參數passprint('name:', name, 'age:', age, 'other:', kw)person1('Jack', 24, city='Beijing', addr='Chaoyang', zipcode=123456)# 如果要限制關鍵字參數的名字,就可以用命名關鍵字參數,例如,只接收city和job作為關鍵字參數 def person2(name,age,*,city,job): # *是分割符print(name,age,city,job)person2('Jack', 24, city='Beijing', job='Engineer')# 命名關鍵字參數可以有缺省值,從而簡化調用 def person3(name, age, *, city='Beijing', job):print(name, age, city, job)person3('Jack', 24, job='Engineer')# 如果函數定義中已經有了一個可變參數,后面跟著的命名關鍵字參數就不再需要一個特殊分隔符*了 def person4(name, age, *args, city, job):print(name, age, args, city, job)# 命名關鍵字參數必須傳入參數名,這和位置參數不同 person4('Jack', 24, city='Beijing', job='Engineer')運行結果:
name: Jack age: 24 other: {'addr': 'Chaoyang', 'city': 'Beijing', 'zipcode': 123456} Jack 24 Beijing Engineer Jack 24 Beijing Engineer Jack 24 () Beijing Engineer這里要注意:如果是python 2.7 版本的話,會出現報錯
def person2(name,age,*,city,job): ^ SyntaxError: invalid syntax但python 3 的版本卻沒問題,看來python的對某些語法的更新還是挺大的。
2.4 參數組合
在Python中定義函數,可以用必選參數、默認參數、可變參數、關鍵字參數和命名關鍵字參數,這5種參數都可以組合使用。但是請注意,參數定義的順序必須是:必選參數、默認參數、可變參數、命名關鍵字參數和關鍵字參數。
# 必選參數、默認參數、可變參數、關鍵字參數 def f1(a, b, c=0, *args, **kw):print('a =', a, 'b =', b, 'c =', c, 'args =', args, 'kw =', kw)# 必選參數、默認參數、可變參數、關鍵字參數和命名關鍵字參數 def f2(a, b, c=0, *, d, **kw):print('a =', a, 'b =', b, 'c =', c, 'd =', d, 'kw =', kw)f1(1, 2) f1(1, 2, c=3) f1(1, 2, 3, 'a', 'b') f1(1, 2, 3, 'a', 'b', x=99) f2(1, 2, d=99, ext=None)args = (1, 2, 3, 4) kw = {'d': 99, 'x': '#'} f1(*args, **kw) args = (1, 2, 3) kw = {'d': 88, 'x': '#'} f2(*args, **kw)運行結果:
a = 1 b = 2 c = 0 args = () kw = {} a = 1 b = 2 c = 3 args = () kw = {} a = 1 b = 2 c = 3 args = ('a', 'b') kw = {} a = 1 b = 2 c = 3 args = ('a', 'b') kw = {'x': 99} a = 1 b = 2 c = 0 d = 99 kw = {'ext': None} a = 1 b = 2 c = 3 args = (4,) kw = {'x': '#', 'd': 99} a = 1 b = 2 c = 3 d = 88 kw = {'x': '#'}參考廖大神的網站:
https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/0014318435599930270c0381a3b44db991cd6d858064ac0000
https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/001431752945034eb82ac80a3e64b9bb4929b16eeed1eb9000
總結
以上是生活随笔為你收集整理的python 装饰器简单笔记(附 *args **kw)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 每天坚持喝酸奶好还是纯牛奶好?
- 下一篇: 如何让土豆不麻?