Closures, decorators

Closure:

If in an outer function, an inner function is defined, and the inner function uses the variables of the outer function, and the outer function returns a reference to the inner function, then the inner function is called a closure. E.g:

    def greet(name):
        def say_hello():
            print('hello my name is %s' % name)
        return say_hello

Complete a calculator with a closure:

    def calculator(option):
        operator = None
        if option == 1:
            def add(x,y):
                return x+y
            operator = add
        elif option == 2:
            def minus(x,y):
                return x-y
            operator = minus
        elif option == 3:
            def multiply(x,y):
                return x*y
            operator = multiply
        else:
            def divide(x,y):
                return x/y
            operator = divide

        return operator

    cal = calculator(1)
    ret = cal(1,2)
    print(ret)

nonlocalKeywords:

If you want to modify the variable of the outer function in the closure, you should use the nonlocalkeyword to identify the variable as a variable of the outer function:

The following code is modified name, but the nonlocalkeyword is not used, and an error will be reported:

def greet(name):
    def say_hello():
        name += 'hello'
        print('hello my name is %s' % name)
    return say_hello

The following code has been modified to nameuse nonlocalkeywords, and no error will be reported:

def greet(name):
    def say_hello():
        nonlocal name
        name += 'hello'
        print('hello my name is %s' % name)
    return say_hello

decorator

Decorators take advantage of the fact that functions can also be passed as parameters and closures, allowing our functions to easily add some code before or after execution. This allows many things to be done, such as @classmethoddecorators can set a normal method as a class method, @staticmethoddecorators can set a normal method as a static method, etc. So after understanding the principle of the decorator, we can customize the decorator to achieve our own needs.

understand:

Take the example of website development. In website development, it is often encountered that some pages need to be logged in before they can be accessed. Then it is very troublesome to judge every time in the accessed view function, and the code is difficult to maintain. The example is as follows:

user = {
    "is_login": False
}

def edit_user():
    if user['is_login'] == True:
        print('用户名修改成功')
    else:
        print('跳转到登录页面')

def add_article():
    if user['is_login'] == True:
        print('添加文章成功')
    else:
        print('跳转到登录页面')

edit_user()
add_article()

There are only two functions above. If the website becomes larger and larger in the future, and the place where judgment needs to be made becomes larger and larger, then this judgment will be very inefficient and difficult to maintain, so at this time we can use the decorator to solve it:

def edit_user():
    print('用户名修改成功')
@login_required
def add_article():
    print('添加文章成功')

def login_required(func):

    def wrapper():
        if user['is_login'] == True:
            func()
        else:
            print('跳转到登录页面')

    return wrapper

edit_user() == login_required(edit_user)() == wrapper()
add_article() == login_required(add_article)() == wrapper()

The decorated function takes parameters:

It is also possible that in the decorated function, the parameters are not fixed, so writing a fixed parameter at this time cannot become a general decorator. At this time, it can be used *argsand **kwargscombined to include all parameters:

def login_required(func):

    def wrapper(*args,**kwargs):
        if user['is_login'] == True:
            func(*args,**kwargs)
        else:
            print('跳转到登录页面')

    return wrapper

@login_required
def edit_user(username):
    print('用户名修改成功:%s'%username)

edit_user()

Decorator with parameters:

Decorators can also be passed parameters. It's just that if you pass parameters to the decorator, then you need to write two methods in this decorator. The sample code is as follows:

def login_required(site='front'):
    def outter_wrapper(func):
        def inner_wrapper(*args,**kwargs):
            if site == 'front':
                if user['is_login'] == True:
                    print('进入到前台了')
                    func(*args,**kwargs)
                else:
                    print('跳转到前台的首页')
            else:
                if user['is_login'] == True:
                    print('进入到后台了')
                    func(*args,**kwargs)
                else:
                    print('跳转到后台的首页')
        return inner_wrappre
    return outter_wrapper


@login_required('front')
def edit_user():
    print('用户名修改成功')

@login_required('front')
def add_article():
    print('添加文章成功')

edit_user()

wraps decorator:

采用之前的装饰器,会让我们的函数失去一些属性,比如__name__,这样在一些代码中会产生错误,比如Flask开发中。如果我们想要用装饰器,并且仍想保留函数的一些属性,比如__name__,那么可以使用wraps装饰器,以下是没有使用wraps装饰器的代码:

def login_required(func):

    def wrapper(*args,**kwargs):
        if user['is_login'] == True:
            func(*args,**kwargs)
        else:
            print('跳转到登录页面')

    return wrapper

@login_required
def edit_user(username):
    print('用户名修改成功:%s'%username)


edit_user()
print(edit_user.__name__)
# 打印wrapper

以下再使用wraps装饰器,来优化代码:

from functools import wraps

def login_required(func):
    @wraps(func)
    def wrapper(*args,**kwargs):
        if user['is_login'] == True:
            func(*args,**kwargs)
        else:
            print('跳转到登录页面')

    return wrapper

@login_required
def edit_user(username):
    print('用户名修改成功:%s'%username)


edit_user()
print(edit_user.__name__)
# 打印edit_user

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325151316&siteId=291194637