你好呀~

函数式编程之装饰器

一. 前言

  借用比较经典的两段话,自行理解。

  “函数式编程关心数据的映射,命令式编程关心解决问题的步骤”

  “什么面向对象,什么函数式,都是看待问题的一种方式,是世界观。面向对象就像把所有的东西都看作独立的个体,它们可以被归类,有自己的状态,可以互相发消息。面向对象编程思维就是设计好一个个对象,然后自己亲手去“摆弄”它们。谁什么时间干什么,安排的明明白白。而函数式则是把世界看成一个整体。就像我们高中学物理的动力学似的,给定一个初始状态,根据牛顿动力学定律,整个体系之后的运动都是确定的。是一个个具体的运动规则应用在整个体系之上,整个体系被运动规则驱动,做着完全可预测的工作。所以函数式当然没有什么变量,没有什么副作用,因为我们是物理学家,我们在用规则刻画整个世界。我们没有什么对象,没有什么消息,有的只是【一切】——>【规则】——>【[新的一切】。”

 

二. 装饰器

  装饰器是函数式编程的表现形式,下面通过代码体验一下装饰器。

  装饰器——在不更改原函数的代码的前提下给函数增加新的功能,特殊之处在于它的返回值也是一个函数!

 

三. 闭包示例代码

复制代码
def fun1(name1):
    def fun2(name2):  # 4.hello传到这儿了,函数这东西不调用就不执行
        print(name1 + name2)

    print('2')  # 1.上面函数没调用就不执行,直接从这儿开始
    return fun2  # 2写的是函数名,返回地址


a = fun1('tom')
a('hello')  # 3指向fun1的返回值即fun2('hello')
a('hi')  # 5同上
# 通过闭包更改外部函数值用nonlocal arg
def func_out(num1):
    def func_inner(num2):
        nonlocal num1  # 可以改变这个值
        num1 = num1 + num2
        print("num1:", num1)

    print(num1)
    func_inner(1)  # 之所以这样,因为得跑一遍才能改呀,直接打印num1,数据流没跑到那儿肯定没修改。
    print(num1)
    return func_inner


f = func_out(1)
f(2)
# 装饰器基础结构
def check(fn):
    def inner():
        print("请先登录....")
        fn()  # 5指向comment()

    return inner  # 1指向下面的调用者comment


def comment():
    print("发表评论")  # 6


comment = check(comment)  # 2 comment装的是inner函数的地址。可改成@check即装饰器,放在被装饰方法comment()的上方。
comment()  # 3指向inner()# 通用装饰器
复制代码

 

四. 普通装饰器1

复制代码
import time


# 普通的装饰器
def show_time(func):  # 第一个参数永远是目标函数名(不干扰的函数)
    # 这里可以写多层
    def wrapper(*args, **kwargs):  # 多个参数没关系的
        star_time = time.time()
        my_func = func(*args, **kwargs)  # 目标函数可以调整位置以改变执行顺序
        end_time = time.time() - star_time  # 统计函数运行时间的功能
        print("总用时 ", end_time)
        return my_func  # 指向函数,这里可以不用return。中间直接执行函数不用赋值给变量

    return wrapper  # 指向内层函数名


@show_time
def say_hello(username):
    time.sleep(0.33)
    print("hello!", username)


say_hello("chrisiven")
复制代码

 

五. 普通装饰器2

复制代码
# (包含了不定长参数、带返回值函数;多debug,先执行两个装饰器,跑没头了,给调用它的人)

def logging(fn):
    def inner(*args, **kwargs):
        print("--正在努力计算--")
        result = fn(*args, **kwargs)  # 藏的有点深啊,所以下面不必再写sum_num()这个指向inner的方法。
        return result

    return inner


@logging
def sum_num(*args, **kwargs):
    result = 0
    for value in args:
        result += value
        print(result)
    for value in kwargs.values():
        result += value
        print(result)
    return result


@logging
def subtraction(a, b):
    result = a - b
    print(result)


result = sum_num(1, 2, a=10)
print(result)
subtraction(4, 2)


check=Check(print)    #也可以改input,拓展:上面args[0]('注册')表示print('注册'),间接表明一切皆对象。
check()
复制代码

 

六. 多装饰器

复制代码
# 多装饰器
def make_div(func):
    """对被装饰的函数的返回值 div标签"""

    def inner(*args, **kwargs):
        return "<div>" + func() + "</div>"

    return inner


def make_p(func):
    """对被装饰的函数的返回值 p标签"""

    def inner(*args, **kwargs):
        return "<p>" + func() + "</p>"

    return inner


# 装饰过程: 1 content = make_p(content) 2 content = make_div(content)
# content = make_div(make_p(content))
@make_div
@make_p
def content():
    return "你好哈哈"


result = content()
print(result)
复制代码

 

七. 带参装饰器

复制代码
def show_times(logger):  # 你传递的数据
    def wrapper(func):  # 你的函数
        def exec(*args, **kwargs):  # 目标函数参数,如果有的话
            print(args, kwargs)
            print("已经被{}控制".format(logger))
            my_func = func(*args, **kwargs)
            return my_func

        return exec

    return wrapper


@show_times("logger")  # 在定义你的主函数时进行传递。
def say_hello(username):
    print("hello,{}".format(username))


say_hello("chrisiven")
复制代码

 

八. 类装饰器

复制代码
import time


# 类装饰器
class Check(object):
    def __init__(self, fn):
        # 初始化操作在此完成
        self.__fn = fn

    # 实现__call__方法,表示对象是一个可调用对象,可以像调用函数一样进行调用。
    def __call__(self, *args, **kwargs):
        # 添加装饰功能
        print("请先登陆...")
        self.__fn('sdf')
@Check
def comment():
    print("发表评论")
comment()
复制代码

 

九. 装饰器传参

复制代码
# 装饰器传参
# 需要多余两层的嵌套,多少层没有关系,重点关注装饰的那一层是谁,在这里装饰层是warpper。a,b,c用来调试用

def deprecated(new_fun_name):
    a = new_fun_name  # 1
    print('a:', a)

    def warpper(fun):  # 2, 4
        b = fun.__name__  # 5
        print('b:', b)

        def inner(*args):  # 7
            c = args  # 12
            print('c:', c)
            return fun(*args)  # 13, 16

        return inner  # 8

    return warpper  # 3


@deprecated('add')  # 4,9, 14
def add_fun(x, y):
    return x + y  # 10, 6, 15


if __name__ == "__main__":  # 10
    res = add_fun(2, 2)  # 5, 11, 17
    print(res)  # 18-over
复制代码

 

作者留言

  原创不宜,如果觉得本文对你有帮助,记得打赏作者噢O(∩_∩)O,你的一点点爱心是我创作路上最大的动力~

 

 

 

posted @   测神  阅读(388)  评论(0编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
点击右上角即可分享
微信分享提示