欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程语言 > python >内容正文

python

python 装饰器简单笔记(附 *args **kw)

发布时间:2024/9/20 python 47 豆豆
生活随笔 收集整理的这篇文章主要介绍了 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 now3

2. 函数的参数

这里最好使用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) 14

2.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)的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。