Python中函数的使用
在Python中,一切都可以看作一个对象,因此,函数也是一个对象。函数可以被传递给一个变量,可以作为另一个函数的参数,还可以作为函数的返回值。
- 函数传递给变量
def Hello():
return 'Hello'
f = func # 将函数赋值给一个变量
print(f)
print(f()) # 执行函数(在函数名后面带上括号才是执行函数)
f = func() # 执行函数,并将返回值赋值给变量f
print(f)
# 输出
# <function func at 0x7efe6450ed08>
# Hello
# Hello
- 函数作为参数传递给另一个函数
def Hello():
return 'Hello'
def callHello(func):
print('Hey')
print(func())
callHello(Hello)
# 输出
# Hey
# Hello
- 函数作为返回值
def Hello():
def Hi():
return 'Hi'
return Hi()
f = Hello()
print(f)
# 输出
# Hi
Python函数装饰器
装饰器(decorators)是一个可以对其它函数进行修改的函数。通过装饰器,不需要对原函数进行修改,提高了程序的可读性和开发效率。装饰器的使用:
def decorator(func):
def wrapper():
print('wrapper')
func()
return wrapper
@decorator
def Hello():
print('Hello')
Hello()
# 输出
# wrapper
# Hello
# wrapper
在上面的代码中,@decorator的作用等价于下面代码中的Hello = decorator(Hello)。@decorator装饰器的作用等价与把Hello函数作为参数传给decorator函数,然后将返回值传递给Hello。而decorator函数的返回值是wrapper函数,所以,最后执行Hello()相当于执行wrapper()函数。
def decorator(func):
def wrapper():
print('wrapper')
func()
return wrapper
def Hello():
print('Hello')
Hello = decorator(Hello)
Hello()
# 输出
# wrapper
# Hello
但是这样有一个问题,就是Hello函数实际上发生了改变,不再是原来的Hello函数,变成了wrapper函数。可以验证一下。
import functools
def decorator(func):
def wrapper():
print('wrapper')
func()
return wrapper
@decorator
def Hello():
print('Hello')
Hello()
print(Hello.__name__)
# 输出
# wrapper
# Hello
# wrapper
为了解决这个问题,可以用内置的装饰器@functools.wrap,它会保留原函数的信息,仅仅把原函数的信息拷贝到对应的装饰器函数中。
import functools
def decorator(func):
@functools.wraps(func)
def wrapper():
print('wrapper')
func()
return wrapper
@decorator
def Hello():
print('Hello')
Hello()
print(Hello.__name__)
# 输出
# Hello
# Hello
带参数的Python函数装饰器
上面被装饰器修饰的函数都是未带参数,如果函数带有参数该如何处理?一个简单的方式是可以在对应的装饰器函数中带上相同数量的参数。
import functools
def decorator(func):
@functools.wraps(func)
def wrapper(info):
print('wrapper')
func(info)
return wrapper
@decorator
def Hello(info):
print(info)
Hello('Hello')
# 输出
# wrapper
# Hello
如果有另一个函数也需要使用decorator装饰器,但是这个函数不止一个参数,又该怎么解决呢?例如:
@decorator
def Hello(info1, info2, info3):
...
通常情况下,我们会使用 *arg 和 *kwargs 作为装饰器中wrapper()函数的参数,*arg 和 *kwargs 表示函数可以接受任意数量和类型的参数。这样一来,上面例子中的装饰器就可以写成这种形式:
import functools
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
print('wrapper')
func(*args, **kwargs)
return wrapper
@decorator
def Hello(info):
print(info)
Hello('Hello')
# 输出
# wrapper
# Hello
装饰器的使用场景
授权(Authorization)
装饰器能有助于检查某个人是否被授权去使用一个web应用的端点(endpoint)。这里是一个例子来使用基于装饰器的授权:
from functools import wraps
def requires_auth(f):
@wraps(f)
def decorated(*args, **kwargs):
auth = request.authorization
if not auth or not check_auth(auth.username, auth.password):
authenticate()
return f(*args, **kwargs)
return decorated
日志(Logging)
from functools import wraps
def logit(func):
@wraps(func)
def with_logging(*args, **kwargs):
print(func.__name__ + " was called")
return func(*args, **kwargs)
return with_logging
@logit
def addition_func(x):
"""Do some math."""
return x + x
result = addition_func(4)
# Output: addition_func was called
使用场景中的两个例子来源于参考资料:
https://eastlakeside.gitbooks.io/interpy-zh/content/decorators/auth.html