python函数与装饰器
一、名字空间与作用域
1.名字空间
名字空间:赋值语句创建了约束,用来存储约束的dict被称为名字空间
赋值语句的行为:1.分别在堆和栈中创建obj与name
2.将obj与name进行绑定
注:具有赋值行为的语句均可以称为赋值语句,如class A(),def a(),import a等
名字空间的划分:local、global、builtin(用来存储module层次的约束)
2.名字空间的可见性
1 a = 1 2 def func(): 3 print a #UnbundlocalError 4 a = 2 5 print a # 1
作用域:约束的作用域仅仅由源程序的文本决定,而不是在运行时动态决定的。因此,python具有静态作用域。
作用域与名字空间的关系:作用域在静态时已决定了名字空间中的name,但name所对应的obj在动态时决定。
注:1、变量能否访问由是否处于同一作用域决定(编译时处理),访问所得值在运行时确定。
2、由一个赋值语句引用的名字在这个赋值语句所在的作用域里是可见的,与代码顺序无关。
3.嵌套规则
LGB:由赋值语句引进的名字在这个赋值语句的内部嵌套的作用域内都是可见的,除非内部作用域中有相同的名字将其屏蔽。
LEGB:
1 a = 1 2 def func(): 3 a = 2 4 def l(): 5 print a 6 return l 7 f = func() 8 f() #输出结果为2
闭包:a = 2,def l均处于func内的同一作用域中,执行f = func()时会将其进行捆绑,并将捆绑后的结果返回。这个捆绑起来的整体即为闭包。
二、函数
1.函数对象的实现 ———— PyFuncionObject
PyFuncionObject:python运行时动态产生,即执行def语句时创建。在PyFunctionObject中储存着函数运行时所需的动态信息。
注:每调用一次函数就会创建一个PyFunc,因为函数调用时具有不同的上下文环境。
2.函数实现上的分离
1 def func(): 2 a = 1 3 def f(): 4 print a 5 return f 6 func()()
对于def f(),在虚拟机中其声明与实现是分离的。声明是在func函数名字空间中的一条约束,而函数体则是一个绑定了上下文信息的PyFunc
函数的参数传递机制:根据参数对象为可变对象还是不可变对象来表现为值传递还是地址传递。
参数种类:参数种类多达5种。分别为必选参数、默认参数、可变参数、命名关键字参数和关键字参数,在参数列表中的位置也需要如此。对于任意函数,都可以通过类似func(*args, **kw)的形式调用它。
三、装饰器
1、原理:
最内嵌套作用域规则(LGB)
2、实现:
最简单的装饰器
1 def f(func): 2 def g(): 3 print 'g..' 4 func() 5 return g 6 7 @f 8 def a(): 9 print 'a'
带参数的装饰器
#-*- encoding: utf8 -*- from functools import wraps import logging def logged(level,name=None,message=None): def decorate(func): logname = name if name else func.__module__ log = logging.getLogger(logname) logmsg = message if message else func.__name__ @wraps(func) def wrapper(*args,**kwargs): print args print kwargs log.log(level,logmsg) return func(*args,**kwargs) return wrapper return decorate @logged(logging.DEBUG) def add(x,y): return x + y @logged(logging.CRITICAL,'example') def spam(): print 'spam' add(3,4) ==> logged(logging.DEBUG)(add)(3,4) #将函数对象作为参数传进修饰器函数中 #被装饰的函数只是作为参数 在装饰器函数中只返回函数对象使用add()(3,4) 调用也可以 #函数wrapper以外的内容只会在定义被装饰的函数时执行一次,仅wrapper函数内的内容才会随着被装饰的函数的调用而执行。即定义被装饰函数时就已执行logged(logging.DEBUG)(add),以后的每次调用只会执行(3,4)部分 ''' 注:1.装饰器函数logged接收装饰器参数,提供闭包时的变量环境装饰器内的函数decorate接收被装饰的函数的对象wrapper函数通过*args,**kwargs接收被装饰函数的参数 2.一层函数一个return,最终返回最底层函数的对象 3.构建了一个两层的闭包环境。内层闭包环境可以访问外层闭包环境,外层闭包环境不可以访问内层 4.通过使用wraps装饰器,可以保证func的元数据不变 '''
注:1、闭包用于绑定运行时环境。
2、装饰器用于对函数重新进行封装,在函数执行前后添加操作。