Python的学习之旅———函数对象函数嵌套名称空间与作用域装饰器

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python的学习之旅———函数对象函数嵌套名称空间与作用域装饰器相关的知识,希望对你有一定的参考价值。

一 函数对象

1 可以被引用

2 可以当作参数传递

3 返回值可以是函数

4 可以当作容器类型的元素

1 def foo():
2     print(from foo)
3  
4 func=foo
5  
6 print(foo)
7 print(func)
8 func()

名称空间:存放名字的地方,准确的说名称空间是存放名字与变量值绑定关系的地方

一、名称空间又分为:

  内置名称空间:在python解释器启动时产生,存放一些python内置的名字

  全局名称空间:在执行文件时产生,存放文件级别定义的名字

  局部名称空间:在执行文件的过程中,如果调用了函数,则会产生该函数的局部名称空间
  用来存放该函数内定义的名字,该名字在函数调用时生效,在函数调用结束后失效

二、加载顺序

  加载顺序:内置--->全局--->局部

三、名字的查找顺序

  局部->全局->内置

四、作用域

  定义:作用的范围

一、分为

全局作用域:全局存活,全局有效:可以用globals()查看

局部作用域:临时存活,局部有效可以用locals()查看

二、改变全局变量

1、可以用global在局部改变全局变量

声明全局变量,如果在局部要对全局变量修改,需要在局部也要先声明该全局变量:

2、可变变量可以不需要global在函数内进行修改

l=[]
def f2():
    l.append(‘f2‘)

f2()
print(l)

3、、nonlocal关键字用来在函数或其他作用域中使用外层(非全局)变量

三、作用域关系

在函数定义时就已经固定于调用位置无关,在调用函数时,必须回到函数原来定义的位置去找作用域关系

 

LEGB 代表名字查找顺序: locals -> enclosing function -> globals -> __builtins__

locals是函数内的名字空间,包括局部变量和形参

enclosing 外部嵌套函数的名字空间(闭包中常见)

globals 全局变量,函数定义所在模块的名字空间

builtins 内置模块的名字空间

四 闭包函数

内部函数包含外部作用域而非全局作用域的引用。

闭包函数的依据是,函数内部未找到变量相应的值时,会先向上一级函数中寻找

变量值。

二 闭包的意义与应用

为了装饰器做准备 (我是这么觉得的)

五 装饰器

装饰器他人的器具,本身可以是任意可调用对象,被装饰者也可以是任意可调用对象。

强调装饰器的原则:

1 不修改被装饰对象的源代码

2 不修改被装饰对象的调用方式

装饰器的目标:在遵循1和2的前提下,为被装饰对象添加上新功能

 

装饰器的原则:在不修改函数调用方式 和函数本身代码的情况下。增加新功能开放封闭原则,对扩展是开放的,对修改是封闭的。

无参装饰器

 1 import time
 2 
 3 def timmer(func):
 4     # func=index #最原始的index函数的内存地址
 5     def inner():
 6         start_time=time.time()
 7         func()
 8         stop_time=time.time()
 9         print(run time is :[%s] %(stop_time-start_time))
10     return inner
11 
12 @timmer #index=timmer(index)
13 def index():
14     time.sleep(3)
15     print(welcome to index page)
16 index()

有几点是关键  代码在执行到@timmer 做了两件事1将 index()函数名‘index’传给timmer 于是有了  timmer(index),2将timmer()赋值给了 index,(在python中变量名是可以反复使用的,这种操作我觉得就是死皮赖脸的做到调用方式不变的目的)index=timmer()

timmer是一个闭包函数,所以有了 4 # func=index #最原始的index函数的内存地址 因为有闭包函数的特性,所以inner在内部的函数func()在寻找func值的时候会向上一层寻找

于是找到了 func=index。这样就有了inner()内部函数 func()变成了 index(),而inner函数最后又将自己return给timmer() 

这时index=timmer()实际上=inner 此时 @timmer的任务就完成了,代码直接跳到16行进行index() 此时的index()==inner().

接下来的顺序 5 -6-7-14-15-8-9.

装饰器修订

 1 import time
 2 from functools import wraps
 3 
 4 def timmer(func):
 5     @wraps(func)              #help等功能
 6     def inner(*args,**kwargs):
 7         start_time=time.time()
 8         res=func(*args,**kwargs)
 9         stop_time=time.time()
10         print(run time is :[%s] %(stop_time-start_time))
11         return res
12 
13     return inner
14 @timmer
15 def index():
16     ‘‘‘
17     index function
18     :return:
19     ‘‘‘
20     time.sleep(3)
21     print(welcome to index page)
22     return 123
23 
24 @timmer #home=timmer(home) #home=inner
25 def home(name):
26     time.sleep(2)
27     print(welcome %s to home page %name)
28     return 456

 有参装饰器

 1 import time
 2 current_status={user:None,login_status:False}
 3 def auth(egine=file):
 4     # egine=‘file‘
 5     def wrapper(func):
 6         def inner(*args,**kwargs):
 7             if current_status[user] and current_status[login_status]:
 8                 res = func(*args, **kwargs)
 9                 return res
10 
11             if egine == file:
12                 u=egon
13                 p=123
14             elif egine == mysql:
15                 print(mysql auth)
16                 u = egon
17                 p = 123
18             elif egine == ldap:
19                 print(ldap auth)
20             else:
21                 pass
22             name = input(username>>:).strip()
23             pwd = input(password>>:).strip()
24             if name == u and pwd == p:
25                 print(login successfull)
26                 current_status[user] = name
27                 current_status[login_status] = True
28                 res = func(*args, **kwargs)
29                 return res
30         return inner
31     return wrapper
32 @auth(egine=ldap) #@wrapper #index=wrapper(index) #index=inner
33 def index():
34     time.sleep(3)
35     print(welcome to index page)
36     return 123

wrapper 是无参装饰器,现在wrapper内部需要参数egine,所以需要想办法给egine传参,那么我们就用到了闭包函数.wrapper外面再包一个参数,于是有了auth(egine) ,装饰的时候会写为

@auth(egine) 上面代码写成@auth(egine=‘file‘),只是给了一个默认的初始值.在运行代码时候,见到@auth(egine=‘file‘) 先忘了他是装饰器 先执行auth(egine=‘file‘)函数 于是得到了return出来的wrapper 于是有了@wrapper 也就是我们的无参装饰器.

所以有参装饰器的本质 就是无参装饰器的闭包函数.装饰器最多是三层就够了.

装饰器是有顺序的.修饰下面的代码(如果下面还有多个装饰器).

有参装饰器有三层  

1外层  传参给内部的核心功能

2 中层 作用不改变被装饰函数调用方式

3 核心层 是内部功能层




以上是关于Python的学习之旅———函数对象函数嵌套名称空间与作用域装饰器的主要内容,如果未能解决你的问题,请参考以下文章

python--函数的返回值函数参数的使用名称空间与作用域函数嵌套函数对象

函数对象函数嵌套名称空间与作用域装饰器

学习python的第二天之函数2.0

python学习之旅2(函数进阶)

可变长参数函数对象嵌套名称空间和作用域

Python之旅的第3²天(内置函数文件基本打开关闭)