装饰器

*****装饰器攻坚前置任务

# 1. *args, **kwargs
def index(x, y):
    print(x, y)

def wrapper(*args, **kwargs):
    index(*args, **kwargs)  # 1.wrapper传的实参是什么形式会原封不动的传到index中 2.wrapper传参受限于index定义阶段形参的规则

wrapper(1, 2)

# 2. 名称空间与作用域: 名称空间的'嵌套'关系实在函数定义阶段产生的, 也可以说是检测语法的受确定的.

# 3. 函数对象: 可以把函数当作参数传入. 可以把函数当作返回值返回.
def index():
    return 123

def bar(func):  
    func()

bar(index)

# 4. 函数嵌套定义
def outer():
    def wrapper():  # wrapper在函数outer内定义, 把wrapper当作返回值返回到全局
        pass
    return wrapper

# 5. 闭包函数
def outer(x):  # 把值x包给wrapper函数
    # x = 1
    def wrapper():
        print(x)
    return wrapper
f = outer(1)
f()

  

什么是装饰器

  • '装饰': 代指被装饰对象添加新功能
  • '器': 代指器具/工具.

可以理解为定义一个函数 合到一起

总结(重点): 装饰器指的就是定义一个函数, 用来为其他函数添加新功能.

为何要用装饰器?

软件的设计原则

软件的设计应该遵守开发封闭原则,即对扩展时开放的,对修改是封闭的.

  • 对扩展开放: 对新的需求或变化, 可以对现有代码进行扩展开放.
  • 对修改封闭: 对象设计完成, 就可以独立完成其工作, 对修改原代码封闭.

总结(重点): 开放: 拓展新功能开放 封闭: 修改源代码封闭

 

装饰器的作用(重点): 不修改被装饰对象源代码和调用方式的前提下为被装饰对象添加新功能.

 

使用装饰器的原因:

  1. 软件包含的所有功能的源代码和调用方式, 都应该避免被修改, 否者一旦改错, 极有可能产生连锁反应, 最终导致程序奔溃.
  2. 上线后的软件, 新需求或者变化层出不穷, 我们必须提供扩展的可能性

 

装饰器的实现: 函数嵌套 + 函数对象 + 闭包函数

  • 补充: time模块下的 time.time()功能
import time

print(time.time())   # time.time()返回的值是时间戳. 以1970年作为起始, 到现在时间为结束. 单位秒
# 历史补充: 1970年是unix元年(10.25)

  

无参装饰器的实现
# 需求: 不修改index源代码和调用方式的前提下为index添加统计时间的功能

  

import time

def foo(x):
    print("其实我这里有很多代码,但是你看不到")
    time.sleep(3)
    return x
    
# 1、我们直接在函数内部进行更改。
def foo(x):
    start_time = time.time()
    print("其实我这里有很多代码,但是你看不到")
    time.sleep(3)
    stop_time = time.time()
    process_time = stop_time - start_time
    print(process_time)
    return x

 这时候虽然我们增加了功能,但是我们已经违反了开放封闭原则,所以失败。

# 2、利用函数的嵌套定义来直接增加新功能

def outer(x):
    start_time = time.time()
    foo(x)
    stop_time = time.time()
    process_time = stop_time - start_time
    print(process_time)
    return x

我们同样实现了功能,调用方式改变,源代码没变。

# 3、利用闭包函数来修改

def outer(foo):
    def inter(x):
        start_time = time.time()
        res = foo(x)
        stop_time = time.time()
        process_time = stop_time - start_time
        print(process_time)
        return res
    return inter

foo = outer(foo)
foo(x)

上述已经实现了不更改函数源码,不更改调用方式了,但是函数被写死了

如果用来修饰多个函数呢?这些函数又有不同个数的参数呢

# 终极版装饰器的诞生。
def outer(func):
    def inter(*args,**kwargs):
        start_time = time.time()
        res = func(*args,**kwargs)
        stop_time = time.time()
        process_time = stop_time - start_time
        print(process_time)
        return res
    return inter

foo = outer(foo)

  

这是利用星号在形参和实参不同的作用来实现的。

自此,装饰器就写好了,遵守开放封闭原则,让用户在不知情的情况下,完成了函数的更新。

要想掌握装饰器,必须弄懂闭包函数这些前置只是,如果还是不太懂,就继续看看闭包函数板块和参数的知识。

# 装饰器的模板。
def outer(func):
	def inter(*args,**kwargs):
		res = func(*args,**kwargs)
		return res
	return inter

  

添加装饰器的时候,可以根据模板然后在inter函数里面添加相关功能。

当然,还有一点就是语法糖的使用,我们可以将装饰器的赋值转成在被修饰函数上一行添加@装饰器名。

# 语法糖:在被修饰函数上一行添加@装饰器名。
@outer
def foo(x):
	print(x)

  

 

 

 

 

上一篇:JAVA基础系列:内部类获取外部类的成员变量


下一篇:CDS view里inner join, left outer join和association的区别