zoukankan      html  css  js  c++  java
  • 浅析python中的装饰器decorator

    最近学习python,其中decorator比较难理解,遂写一篇来总结供后续查阅。

           定义一个函数,想在运行时动态的改变函数的功能,又不想改变函数本身的代码,可以使用高阶函数(可以使用函数作为参数)

      装饰器函数可以简化代码,避免每个函数编写重复的代码,也可以用在python web开发中进行登录限制。

    1,一般的函数调用-硬编码调用,代码中直接调用函数(直接调用原函数):

    def func1():
        print ("func1")
        
    def func2():
        print("before")
        func1()
        print("after")
    
    func2()

    输出为:

    2,python中可将函数作为参数进行传递(高阶函数):

    def func1():
        print("func1")
    
    def wrapper(func): #装饰器函数
        print("before")
        func()
        print("after")
        return func  #如果不写return func,函数会自动返回,默认为0
    
    func1=wrapper(func1)

     调用结果同上。

    wrapper函数最后如果不返回func,再次调用func1,则会包以下错误TypeError: 'NoneType' object is not callable:

     3,python中的decorator中可以简化上述调用:

    def wrapper(func):
        print("before")
        func()
        print("after")
        return func
    
    @wrapper
    def func1():
        print("func1")

    直接执行,结果同上。

    4,这种装饰器执行一次调用一次,我们如果希望显示调用,则可以在函数内部封装一层:

    def wrapper(func):
        def inner():
            print("before")
            func()
            print("after")
        return inner
    
    @wrapper
    def f():
        print("call f")
    
    f()#显示调用

     5,上面是无参数的装饰器,python中可以实现有参装饰器调用:

    def wrapper(func):
        def inner(a,b):
            print("before wrapper")
            func(a,b)
            print("after wrapper")
        return inner
    
    @wrapper
    def f(a,b):
        print ("call f: a+b=%d"% (a+b) )
    
    f(2,3) # f=wrapper(f)=inner

    6,有时候,不确定装饰器中参数个数的情况下,就不能使用一般参数、默认参数了,可以使用(*args, **kwargs)来自动适应变参和命名参数:

    #coding:utf-8
    def wrapper(func):
        def inner(*args, **kwargs):
            print("before %s"%func.__name__)
            result=func(*args,**kwargs)
            print("result of %s is %d"%(func.__name__,result))
        return inner
    
    @wrapper
    def f1(a,b):
        print("call f1")
        return a+b
    @wrapper
    def f2(a,b,c):
        print("call f2")
        return a+b+c
    
    f1(1,2)
    f2(2,3,4)

    7,使用functools.wraps在装饰器中包裹传进来的函数,这样就不会丢失传进来的函数的__name__等属性:

    from functools import wraps
    
    def my_decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            print('wrapper')
            func(*args, **kwargs)
    
        return wrapper
    
    @my_decorator
    def my_fun():
        print('test')
    
    #exec
    my_fun()

     8,装饰器在flask中的应用:

    #只贴出装饰器核心代码
    def login_decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            if session.get('manage_name'):
                return func(*args, **kwargs)
            else:
                return redirect(url_for('login'))
    
        return wrapper
    
    
    @app.route('/post')
    @login_decorator
    def post():
        if request.method == 'GET':
            return render_template('post.html')
        else:
            pass

    具体代码可见我的github

    参考:简书

  • 相关阅读:
    性能监控工具之----PerfMon Metrics Collector
    idea 常用设置记录
    springboot 初体验之踩坑篇
    Interleave controller-jmeter
    js怎么判断一个类型是否为数组类型
    加载完成事件
    Jquery-查找
    Dom-增加、删除
    Dom-修改
    Dom-查找
  • 原文地址:https://www.cnblogs.com/hoaprox/p/9481884.html
Copyright © 2011-2022 走看看