美文网首页
函数的嵌套和作用域,闭包,装饰器

函数的嵌套和作用域,闭包,装饰器

作者: 莫辜负自己的一世韶光 | 来源:发表于2019-03-07 17:27 被阅读0次

函数的嵌套定义

# encoding:utf-8
__author__ = 'Fioman'
__time__ = '2019/3/1 19:05'

def f1():
    print('in f1')
    def f2():
        print('in f2')
    f2()

f1()
# encoding:utf-8
__author__ = 'Fioman'
__time__ = '2019/3/1 19:09'


def f1():
    def f2():
        def f3():
            print('in f3()')
        print('in f2()')
        f3()
    print('in f1()')
    f2()
f1()

nonlocal关键字的作用

在有嵌套的函数中,如果我们内部的函数使用外部的变量的时候,如果只是访问,可以正常的访问.

# encoding:utf-8
__author__ = 'Fioman'
__time__ = '2019/3/1 19:15'
def outsite():
    var = 5
    def inside():
        print(var)
    inside()

outsite()

但是如果要修改的话,必须使用nonlocal关键字进行声明,声明这个变量是外部变量.

# encoding:utf-8
__author__ = 'Fioman'
__time__ = '2019/3/1 19:15'
def outsite():
    var = 5
    def inside():
        # print(var) 这里会报错,nonlocal声明的变量在内部函数之前不能出现.
        nonlocal var
        var = 11
        print(var)
    inside()

outsite()

闭包的概念

首先看一个经典的闭包

# encoding:utf-8
__author__ = 'Fioman'
__time__ = '2019/3/1 19:36'

def outer(arg):
    var = 1
    def inside():
        print(arg,var) #内部函数引用了外部变量
    return inside #外部函数返回的是内部函数

闭包的形成,必须满足三个条件
1. 必须是嵌套函数
2. 内部函数必须引用了外部变量(不是全局变量)
3. 外部函数的返回值必须是内部函数

一句话解释就是,当一个函数被当成对象返回的时候,夹带了外部变量,就形成了一个闭包.

如何理解闭包呢?

闭包的最大意义就是它带了外部函数中的变量,同一个函数可以带不同的外部变量.并且即使这个外部变量所在的外部函数不存在了,这个变量也会一直存在.它存在的方式就是在内部函数对象的closure属性,里面存放了一个元组,保存了所有的外部变量,以及它对应的值.所以内部函数携带的这个外部变量才可以持久的存储和使用.其实外部变量已经不在内存中,只是被内部函数以另外一种方式记录了下来.

如何判断一个函数是不是闭包函数

# encoding:utf-8
__author__ = 'Fioman'
__time__ = '2019/3/1 20:02'
# 输出的__closuer__有cell元素:是闭包

def func():
    name = 'eva'
    def inner():
        print(name)
    print(inner.__closure__)
    return inner

f = func()
f()
name = 'egon'
def func():
    def inner():
        print(name)
    print(inner.__closure__)
    return inner

f = func()
f()

装饰器

装饰器函数是什么?
首先要明白两点:装饰器利用了闭包特性,还利用了函数可以作为参数和返回值使用
装饰器函数是一个嵌套函数,外层函数的返回值必须是被装饰过的函数.

简单的来说,装饰器就是一个包装函数,它本质上是一个闭包函数.一般就是传入一个函数,在不修改原来函数以及其调用方式的前提下为原来的函数增加新的功能.通常的做法是在内层的函数中调用被装饰的函数,然后再调用之前或者之后可以增加额外的代码,来增加一些额外的功能.达到扩展功能的目的.其实装饰器函数本质上是函数名和函数地址的重新绑定.被装饰的函数虽然看起来和原来的函数名字一样,但是在其内存中已经修改了绑定关系,它已经绑定到我们的装饰器函数的内层的那个闭包函数上了.

# encoding:utf-8
__author__ = 'Fioman'
__time__ = '2019/3/1 20:28'

import time

# 装饰器函数
def deco(func):
    def wrapper():
        startTime = time.time()
        func()
        endTime = time.time()
        print('程序执行了{}秒'.format(endTime - startTime))
    return wrapper

@deco
def myfunc():
    print('hello')
    time.sleep(1)
    print('world!')

# @deco的作用就相当于是改变被装饰的函数变量的值,首先将其作为参数传递为装饰器函数,用它的返回值,赋值给被装饰的函数
# myfunc = deco(myfunc) # 相当于是myfunc = wrapper myfunc增加一个统计时间的功能
# 被装饰的函数经过装饰后,其实就变成了装饰器函数的内部函数,也就是闭包函数.

if __name__ == '__main__':
    myfunc()

装饰器的一般定义方式:

# encoding:utf-8
__author__ = 'Fioman'
__time__ = '2019/3/1 20:46'


# 可以传递参数的装饰器函数
def timer(func):
    def inner(*args, **kwargs):
        '''被装饰函数执行之前要做的事情'''
        re = func(*args, **kwargs)
        # 被装饰函数执行之后要做的事情
        return re
    return inner

# 但是这样有一个问题,就是我们被装饰的函数的一些属性会改变.
@timer
def func1(a,b):
    print(a + b)

@timer
def func2(a):
    print(a)

print(func1.__name__,func2.__name__)

如果不想修改原来的被装饰的函数的name,doc文档结构的话,可以使用@wraps 在functiontoos包中
所以比较规范的装饰器定义如下:

# encoding:utf-8
__author__ = 'Fioman'
__time__ = '2019/3/1 20:57'
from functools import wraps


def user_login_data(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        return func(*args, **kwargs)

    return wrapper


@user_login_data
def f1():
    print('aaa')


@user_login_data
def f2():
    print('bbb')


if __name__ == '__main__':
    print(f1.__name__)
    print(f2.__name__)

Python多个装饰器的执行顺序问题

# encoding:utf-8
__author__ = 'Fioman'
__time__ = '2019/3/7 17:18'

def deco1(func):
    print('outer1')
    def inner1(*args,**kwargs):
        print('inner1')
        func(*args,**kwargs)
    return inner1

def deco2(func):
    print('outer2')
    def inner2(*args,**kwargs):
        print('inner2')
        func(*args,**kwargs)
    return inner2

@deco2
@deco1 # test = deco1(test) inner1   test = deco2(inner1) = inner2()
def test():
    print('test')

if __name__ == '__main__':
    test()

相关文章

  • 函数 二

    1.函数对象 2.函数的嵌套 3.作用域(作用范围) 4.闭包函数 5.装饰器

  • Python装饰器-专题笔记

    学会装饰器,Python更进阶 函数作用域到闭包到装饰器讲解,及闭包和装饰器的运用。 [√] 慕课网Meshare...

  • 装饰器

    装饰器的作用:在不改变原函数的情况下给函数增加功能! 装饰器由闭包和语法糖组成。 闭包 即两个函数嵌套,外部函数返...

  • 如何理解闭包?

    1、定义: 嵌套在函数作用域中的函数,称为闭包函数。该作用域称为闭包环境。通过闭包函数可以访问闭包函数所在函数作用...

  • JavaScript基础 闭包 2

    闭包: 形成闭包的条件:1、函数嵌套函数(有作用域的嵌套)2、内部函数使用了外部的变量/参数 作用:内部函数使用的...

  • Python装饰器与闭包!

    闭包是Python装饰器的基础。要理解闭包,先要了解Python中的变量作用域规则。 变量作用域规则 首先,在函数...

  • Python笔记四 装饰器

    装饰器 = 高阶函数+函数嵌套+闭包 高阶函数 = 参数 or 返回值为函数 函数嵌套 = 在函数中定义函数 闭包...

  • 函数的嵌套和作用域,闭包,装饰器

    函数的嵌套定义 nonlocal关键字的作用 在有嵌套的函数中,如果我们内部的函数使用外部的变量的时候,如果只是访...

  • Python-闭包和修饰器

    作用域 闭包 code: 装饰器 code: 装饰器案例 code:

  • 闭包

    闭包是什么;闭包的作用;闭包的一些特点。 什么是闭包,简单的说就是函数嵌套函数(红宝书),在函数作用域内,可以访问...

网友评论

      本文标题:函数的嵌套和作用域,闭包,装饰器

      本文链接:https://www.haomeiwen.com/subject/hdkquqtx.html