python函数之闭包函数与装饰器

一:函数对象

函数是第一类对象,即函数可以当作数据传递

def f1():
    print('from f1')
def f2():
    print('from f2')
def f3(func):
    return func
f = f1        #函数可以被引用
print(f)      #得到的是函数f1的值(是f1这个函数名指向的值,即函数体的内存地址,而不是函数执行后的返回值),
f()            #直接加对圆括号就可以执行该变量名指向的值(函数体的内存地址)对应的函数体    执行结果:from f1
f3(f2)()     #函数可以作为另一个函数的参数,还可以作为返回值返回    from f2
alist = [f1,f2,f3]   #函数可以当作容器类型(列表,元组,字典等)的元素
alist[0]()        # 执行得到:from f1

二:名称空间与作用域

   名称空间:顾名思义,即存名字的内存空间 

#三类名称空间
内置名称空间:用来存放python解释器内置的名字(如print,len,int等等)
全局名称空间:用来存文件中不在函数内的名字
局部名称空间:用来存定义在函数中的名字

要查找一个变量名,顺序如下(注意不能反着来找!)
局部名称空间 --> 全局名称空间 --> 内置名称空间

    作用域即作用范围,名字(变量名,函数名等)的作用域即该名字的有效范围,在这范围之外无法访问到该名字!

#作用域有全局和局部之分
全局:包括内置名称空间与全局名称空间,即名字全局有效
局部:包括局部名称空间,即名字局部有效

在全局中定义的变量称为全局变量,它全局有效,即在文件的任何地方都有效
在局部中定义的变量称为局部变量,它局部有效,即仅在该函数内有效,在函数外是无效的

三:闭包函数

在一些语言中,在函数中可以(嵌套)定义另一个函数时,如果内部的函数引用了外部的函数的变量,则可能产生闭包。
闭包可以用来在一个函数与一组“私有”变量之间创建关联关系。在给定函数被多次调用的过程中,这些私有变量能够保持其持久性。
----维基百科

    若一个内部函数引用了其外部函数的变量,而且该内部函数被当成对象返回,此时就产生了闭包效果,该内部函数就成了一个闭包函数。闭包函数无论在哪被引用,都优先使用其自己的私有变量(其外部包裹函数中的局部变量,此时这些局部变量只能被该闭包函数使用,在其他地方都是无效的,所以自然就成了该闭包函数的私有变量)

#内部函数inner()在这就是一个闭包函数
def outer(a):   #函数的参数也是在函数里面的变量,属于该函数的局部变量
    def inner():
        print(a)       #内部函数inner使用了外部函数outer的变量a
    return inner      #内部函数inner被当成对象返回

f = outer(5)   #f=inner
a = 6
f()     #此时,inner()使用的a还是outer函数内的局部变量a,这个局部变量a实际上成了inner函数的私有变量,而不会在这使用上面刚定义的全局变量a

四:装饰器decorator

    写代码需遵循一个原则,即开放封闭原则:对已实现的功能代码块封闭,不让修改;对扩展开发开放,允许扩展

    装饰器就是这么一种谨遵开放封闭原则的开发工具,装饰器本质上是一个闭包函数

#装饰器:1,不修改目标函数的源代码
#        2,不改变目标函数的调用方式
#        3,为目标函数增加新功能
#无参装饰器模板
def decorator(func):         #这里得到原目标函数
    def wrapper(*args,**kwargs):
        return func(*args,**kwargs)
    return wrapper
# 有参装饰器模板
def decorator(arguments):
    def log(func):
        def wrapper(*args,**kwargs):
            return func(*args,**kwargs)
        return wrapper
    return log
# 装饰器语法糖:即在python中正确使用装饰器;在需要使用装饰器的函数前面加上@decorator(需单独占一行),可以同时调用多个装饰器
@decorator1             #同时调多个装饰器,每次调用都单独占一行;注意调用的顺序,调用的顺序不一样,可能产生不同的效果!
@decorator2             #当然,装饰器的定义需要在调用之前
def hello():
    print('hello,world')

函数也是对象,它有__name__等属性,但经过decorator装饰之后的函数,它们的__name__已经从原来的'now'变成了'wrapper',所以,需要把原始函数的__name__等属性复制到wrapper()函数中,否则,有些依赖函数签名的代码执行就会出错。

不需要编写wrapper.__name__ = func.__name__这样的代码,Python内置的functools.wraps就是干这个事的。所以,一个完整的decorator的写法如下:

import functools

def log(func):
    @functools.wraps(func)
    def wrapper(*args, **kw):
        print 'call %s():' % func.__name__
        return func(*args, **kw)
    return wrapper
import functools

def log(text):
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kw):
            print '%s %s():' % (text, func.__name__)
            return func(*args, **kw)
        return wrapper
    return decorator

 

你可能感兴趣的:(Python基础)