目录链接:https://www.jianshu.com/p/e1e201bea601
函数核心
- 一、在 Python 中, 函数是一等公民(first-class citizen) , 函数也是对象。 我们可以把函数赋予变量
def func(message):
print('Got a message: {}'.format(message))
send_message = func # 把函数赋予变量
send_message('hello world')
- 二、可以把函数当作参数, 传入另一个函数中
def get_message(message):
return 'Got a message: ' + message
def root_call(func, message):
print(func(message))
root_call(get_message, 'hello world') # 把函数当作参数
- 三、可以在函数中定义函数, 也就是函数的嵌套
def func(message):
def get_message(message): # 在函数中定义函数
print('Got a message: {}'.format(message))
return get_message(message)
func('hello world')
- 四、函数的返回值也可以是函数对象(闭包)
def func_closure():
def get_message(message): # 可以在函数中定义函数
print('Got a message: {}'.format(message))
return get_message # 函数的返回值也可以是函数对象(闭包)
send_message = func_closure()
send_message('hello world')
简单的装饰器
def my_decorator(func):
def wrapper():
print('wrapper of decorator')
func()
return wrapper
def greet():
print('hello world')
greet = my_decorator(greet)
greet()
变量 greet 指向了内部函数 wrapper(),而内部函数 wrapper() 中又会调用原函数greet(), 因此, 最后调⽤ greet() 时, 就会先打印 'wrapper of decorator' , 然后输出 'helloworld' 。
函数 my_decorator() 就是⼀个装饰器, 它把真正需要执行的函数 greet() 包裹在其中, 并且改变了它的⾏为, 但是原函数 greet() 不变。
更简单、 更优雅的表示:
def my_decorator(func):
def wrapper():
print('wrapper of decorator')
func()
return wrapper
@my_decorator
def greet():
print('hello world')
greet()
@my_decorator 就相当于前面的 greet=my_decorator(greet) 语句, 只不过更加简洁
带有参数的装饰器
原函数 greet() 有参数需要传递给装饰器,一个简单的办法 是在对应的装饰器函数 wrapper() 上, 加上相应的参数。
def my_decorator(func):
def wrapper(message): # 带有参数的装饰器
print('wrapper of decorator')
func(message)
return wrapper
@my_decorator
def greet(message): # 带有参数的装饰器
print(message)
greet('hello world')
这样处理有个问题,如果我另外还有个函数,也需要使用 my_decorator() 装饰器, 但是这个新的函数有两个参数。
通常这种情况下会把 *args 和 **kwargs , 作为装饰器内部函数 wrapper() 的参数。 *args 和 **kwargs , 表示接受任意数量和类型的参数。
def my_decorator(func):
def wrapper(*args, **kwargs):
print('wrapper of decorator')
func(*args, **kwargs)
return wrapper
带有自定义参数的装饰器
装饰器可以接受原函数任意类型和数量的参数, 除此之外, 它还可以接受自己定义的参数。
def repeat(num): # 带有自定义参数的装饰器
def my_decorator(func):
def wrapper(*args, **kwargs):
for i in range(num):
print('wrapper of decorator')
func(*args, **kwargs)
return wrapper
return my_decorator
# 带有自定义参数的装饰器
@repeat(4)
def greet(message):
print(message)
greet('hello world')
原函数还是原函数吗?
def repeat(num):
def my_decorator(func):
def wrapper(*args, **kwargs):
for i in range(num):
print('wrapper of decorator')
func(*args, **kwargs)
return wrapper
return my_decorator
@repeat(4)
def greet(message):
print(message)
print('greet.__name__ = ',greet.__name__)
help(greet)
greet() 函数被装饰以后, 它的元信息变了。 元信息告诉我们“它不再是以前的那个greet() 函数,而是被 wrapper() 函数取代了”。
为了解决这个问题, 通常使用内置的装饰器 @functools.wrap , 它会帮助保留原函数的元信息(也就是将原函数的元信息, 拷贝到对应的装饰器函数中) 。
import functools
def repeat(num):
def my_decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
for i in range(num):
print('wrapper of decorator')
func(*args, **kwargs)
return wrapper
return my_decorator
@repeat(4)
def greet(message):
print(message)
print('greet.__name__ = ',greet.__name__)
help(greet)
类装饰器
类也可以作为装饰器。 类装饰器主要依赖于函数 _call() , 每当你调用一个类的实例时, 函数 call() 就会被执行一次。
class Count:
def __init__(self, func):
self.func = func
self.num_calls = 0
def __call__(self, *args, **kwargs): # 类装饰器
self.num_calls += 1
print('num of calls is: {}'.format(self.num_calls))
return self.func(*args, **kwargs)
@Count
def example():
print("hello world")
example()
example()
装饰器的嵌套
Python 也支持多个装饰器,比如写成下面这样的形式:
@decorator1
@decorator2
@decorator3
def func():
...
其执行顺序是从里到外,等价于
decorator1(decorator2(decorator3(func)))
举个例子:
import functools
def my_decorator1(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
print('execute decorator1')
func(*args, **kwargs)
return wrapper
def my_decorator2(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
print('execute decorator2')
func(*args, **kwargs)
return wrapper
@my_decorator1
@my_decorator2
def greet(message):
print(message)
greet('hello world')
参考资料:
极客时间 Python核心技术与实战学习
Python核心技术与实战(极客时间)链接:
http://gk.link/a/103Sv
GitHub链接:
https://github.com/lichangke/LeetCode
知乎个人首页:
https://www.zhihu.com/people/lichangke/
个人首页:
https://www.jianshu.com/u/3e95c7555dc7
个人Blog:
https://lichangke.github.io/
欢迎大家来一起交流学习