1.一切皆对象
实例
# -*- coding: utf-8 -*-
# @Time : 2022/4/4 9:52
# @File : decoration.py
# @Software : PyCharm
def foo():
print('i am foo')
# 打印函数
print(foo)
# 我们甚至可以将一个函数赋值给一个变量,比如
f = foo;
f()
# 函数对象有一个__name__属性,可以拿到函数的名字
print(f.__name__)
运行结果:
<function foo at 0x0000018BB35C3E20>
i am foo
foo
2.装饰器 装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。
先来看一个简单例子:
def foo():
print('i am foo')
现在有一个新的需求,希望可以记录下函数的执行日志,于是在代码中添加日志代码:
import logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
def foo():
print('i am foo')
logging.info("foo is running")
foo()
运行结果:
i am foo
2022-04-04 10:03:12,378 - root - INFO - foo is running
bar()、bar2()也有类似的需求,怎么做?再写一个logging在bar函数里?这样就造成大量雷同的代码,为了减少重复写代码,我们可以这样做,重新定义一个函数:专门处理日志 ,日志处理完之后再执行真正的业务代码。
import logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
def use_logging(func):
logging.warning("%s is running" % func.__name__)
func()
def foo():
print('i am foo')
def bar():
print('I am bar')
use_logging(foo)
use_logging(bar)
运行结果:
i am foo
I am bar
2022-04-04 10:05:41,269 - root - WARNING - foo is running
2022-04-04 10:05:41,269 - root - WARNING - bar is running
但是现在又有了新问题,调用时不得不改成use_logging(bar),use_logging(foo)。那么有没有更好的方式的呢?当然有,答案就是装饰器。
函数use_logging就是装饰器,它把执行真正业务方法的func包裹在函数里面,看起来像bar被use_logging装饰了。在这个例子中,函数进入和退出时 ,被称为一个横切面(Aspect),这种编程方式被称为面向切面的编程(Aspect-Oriented Programming)。学过Java 的spring框架的同学对这个概念应该一点也不陌生。
# -*- coding: utf-8 -*-
# @Time : 2022/4/4 9:52
# @File : decoration.py
# @Software : PyCharm
import logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
def use_logging(func):
def wrapper(*args, **kwargs):
logging.warning("%s is running" % func.__name__)
return func(*args, **kwargs)
return wrapper
# @符号是装饰器的语法糖,在定义函数的时候使用,避免再一次赋值操作
@use_logging
def foo():
print('i am foo')
@use_logging
def bar():
print('I am bar')
foo()
bar()
装饰器在Python使用如此方便都要归因于Python的函数能像普通的对象一样能作为参数传递给其他函数,可以被赋值给其他变量,可以作为返回值,可以被定义在另外一个函数内。