Python/函数的嵌套和闭包


Python基础--函数的嵌套和闭包

1、名称空间与作用域

 1 名称空间分为:

 

   1 内置名称空间   内置在解释器中的名称

 

   2 全局名称空间   顶头写的名称

 

   3 局部名称空间

 

2 找一个名称的查找顺序:先在局部名称空间找,再到全局名称空间找,再到内置名称空间

 

3 Globals()  查看全局名称空间的内容

 

  Locals()   查看局部名称空间的内容

 

4 全局作用域包含内置名称空间和全局名称空间

 

   局部作用域包含局部名称空间

 

 

1 查看内建名称空间的内容:

 

 

2 作用域

1 x=1
2 def foo():
3     x=100
4     print(x)
5 foo()
6 print(x)

 

输出结果

1 100
2 1

 

 

3 一定要注意函数要先定义,后使用

1 def foo():
2     print("from foo")
3     bar()
4 def bar():
5     print("from bar")
6 foo()

 

输出结果:

1 from foo
2 from ba

 

 

1 def foo():
2     print("from foo")
3     bar()
4 foo()
5 def bar():
6 print("from bar")

 

输出结果:

1 NameError: name 'bar' is not defined  #报错

 

 

4 Globals()  查看全局名称空间的内容

  Locals()   查看局部名称空间的内容

1 x=1
2 def func():
3     print("from func")
4     x=2
5     print(globals())
6     print(locals())
7 func()
8 print(globals())
9 print(locals())

 

输出结果:

1 from func
2 {'x': 1, '__cached__': None...
3 {'x': 2}
4 {'x': 1, '__cached__': None...
5 {'x': 1, '__cached__': None...

 

 

2、函数嵌套与静态嵌套域

嵌套调用

嵌套调用作用:将一个大的功能细化成各种小的函数功能并调用

 1 def my_max(x,y):
 2     res=x if x >y else y
 3     return res
 4 print(my_max(10,100))
 5 def my_max4(a,b,c,d):
 6     res1=my_max(a,b)
 7     res2=my_max(res1,c)
 8     res3=my_max(res2,d)
 9     return res3
10 print(my_max4(1,20,3,4))

 

输出结果:

1 100
2 20

 

在函数内定义的函数 在外面不能用到

1 def f1():
2     def f2():
3         def f3():
4             pass
5     print("---->f1")
6     f2()
7 f2()

 

输出结果:

1 NameError: name 'f2' is not defined  #报错

 

#嵌套定义  

x找值的过程:先在局部名称空间找,再到上一级的局部名称空间找,再到全局名称空间找,再到内置名称空间

 1 x=0
 2 def f1():
 3     #x=1
 4     print("---f1---",x)
 5     def f2():
 6         #x=2
 7         print("---f2---",x)
 8         def f3():
 9             #x=3
10             print("---f3---",x)
11         f3()
12     f2()
13 f1()

 

输出结果:

1 ---f1--- 0
2 ---f2--- 0
3 ---f3--- 0

 

 

3、函数对象

函数被称为第一类对象,函数可以被当做数据传递

(1)函数可以被赋值

直接输出函数名的值: 就是函数在内存中的地址

1 def foo():
2     print("foo")
3 print(foo)

 

输出结果: 

1 <function foo at 0x000000DD32CAAD90>

 

 

函数可以被赋值:将函数名代码的值赋给变量 

1 def foo():
2     print("foo")
3 f=foo
4 print(f)
5 f()

 

输出结果:

1 <function foo at 0x0000003AEBEBAD90>
2 foo

 

(2)函数可以作为参数传递

函数可以作为参数传递

1 def foo():
2     print("foo")
3 def bar(func):
4     print(func)
5     func()
6 print(bar(foo))

 

输出结果:

1 <function foo at 0x000000A351B4AD90>
2 foo
3 None

 

(3)函数可以作为返回值

函数可以作为函数的返回值

1 def foo():
2     print("foo")
3 def bar(func):
4     print(func)
5     func()
6     return func
7 f=bar(foo)
8 print(f)
9 f()

 

输出结果:

1 <function foo at 0x000000BFD82CAD90>
2 foo
3 <function foo at 0x000000BFD82CAD90>
4 foo

 

(4)函数可以作为容器类型的元素

函数作为字典的键的值:

 1 def add():
 2     print("=======>function add")
 3 def search():
 4     print("=======>function search")
 5 def delete():
 6     print("=======>function delete")
 7 def change():
 8     print("=======>function change")
 9 def tell_msg():
10     msg='''
11     search:查询
12     add:添加
13     delete:删除
14     change:修改
15     create:新建
16     '''
17     print(msg)
18 def create():
19     print('=======>function create')
20  
21 cmd_dic={
22     'search':search,
23     'add':add,
24     'delete':delete,
25     'change':change,
26     'create':create
27 }
28 while True:
29     tell_msg()
30     choice=input("please input your choice:")
31     cmd_dic[choice]()

 

 

4、函数闭包

 

(1)函数闭定义

闭包:首先必须是内部定义的函数,该函数包含对外部作用域而不是全局作用域名字的引用

定义:内部函数的代码包含对外部函数的代码的引用,但一定不是对全局作用域的引用

闭包的基本形式是:

  在函数F1中,定义F2,F2只能引用F1定义的变量,之后F1函数返回F2的函数名字

  这样就保证了可以将F1的执行结果赋予给一个变量,该变量可以在之后的任何时刻随时可以运行

使用闭包的好处:自带状态即变量,可以不用传参就用,方便。

闭包(closure)是函数式编程的重要的语法结构。不同的语言实现闭包的方式不同。Python以函数对象为基础,为闭包这一语法结构提供支持的 (我们在特殊方法与多范式中,已经多次看到Python使用对象来实现一些特殊的语法)。Python一切皆对象,函数这一语法结构也是一个对象。在函数对象中,我们像使用一个普通对象一样使用函数对象,比如更改函数对象的名字,或者将函数对象作为参数进行传递。

 (2)简单闭包举例

1 x=1000
2 def f1():
3     x=1
4     def f2():
5         print(x)
6     return f2
7 f=f1()
8 print(f)
9 x=123

 

输出结果:

1 <function f1.<locals>.f2 at 0x000000C02BD1AF28>
2 1

 

(3)闭包的__closure__变量

闭包都有__closure__属性

__closure__对象会返回闭包应用外围作用域的变量信息。f.__closure__保存外围作用域的变量内存地址,f.__closure__[0].cell_contents存放的是外围作用域的变量的值。

对于那些不是闭包的函数对象来说,__closure__ 属性值为 None。

 1 x=1
 2 def f1():
 3     x=1000
 4     y=2
 5     def f2():
 6         y
 7         print(x)
 8     return f2
 9 f=f1()  #f ---> 内部的函数f2
10 f()
11 print(f.__closure__)
12 print(f.__closure__[0])
13 print(f.__closure__[0].cell_contents)
14 print(f.__closure__[1])
15 print(f.__closure__[1].cell_contents)

 

输出结果:

1 1000
2 (<cell at 0x000000429E165D68: int object at 0x000000429E0A9EB0>, <cell at 0x000000429E165D98: int object at 0x0000000059C0EF50>)
3 <cell at 0x000000429E165D68: int object at 0x000000429E0A9EB0>
4 1000
5 <cell at 0x000000429E165D98: int object at 0x0000000059C0EF50>
6 2

 

举例:__closure__ 属性值为 None

1 x=1
2 def f1():
3     def f2():
4         print(x)
5     return f2
6 f=f1()  #f ---> 内部的函数f2
7 f()
8 print(f.__closure__)

 

 输出结果为:

1 1
2 None

 

(4)闭包应用

Windows中cmd中执行pip install requests 安装requests库件

爬baidu网站的程序

1 from  urllib.request import urlopen
2 def get(url):
3     return urlopen(url).read()
4 print(get('http://www.baidu.com'))
5 print(get('http://www/python.org'))

 

将上面”爬百度”的程序修改成闭包模式:

1 from  urllib.request import urlopen
2 def f1(url):
3     def f2():
4         print(urlopen(url).read())
5     return f2
6 baidu=f1('http://www.baidu.com')
7 python=f1('http://www.python.org')
8 baidu()
9 python()

 

一、名称空间和作用域

 名称空间:Python所有有关命名的操作都是在操作名称空间,例如变量名,函数名 1、内置名称空间:Python解释器提供好的功能,解释器启动跟着一起启动,是全局作用域 2、全局名称空间:Python中顶行写的,不在函数内部定义的,都是全局名称空间,在运行的时候会产生名称空间,是全局作用域 3、局部名称空间:在一个小范围定义,只能当前范围及其子空间内运行,例如在函数内部定义的,是局部作用域

二、函数的嵌套

1、函数的嵌套调用 2、函数的嵌套定义
 1 x = 1111111111111111
 2 def f1():
 3     #x=1
 4     print('------>f1 ',x)
 5     def f2():
 6         #x = 2
 7         print('---->f2 ',x)
 8         def f3():
 9             x=3
10             print('-->f3 ',x)
11         f3()     
12     f2()
13 f1()

三、函数的使用

1、函数可以被当做变量赋值
 1 def foo():
 2     print("foo")
 3 print(foo)          #打印foo的内存地址空间,函数的名字在不带小括号时表示的是函数的内存地址
 4 f=foo               #把foo的内存地址空间做值赋值给f变量
 5 print(f)            #打印f,起始就是打印foo的内存地址空间
 6 f()                 #f()事实上就是执行foo函数,等同于foo()
 7 
 8 
 9 打印结果为
10 <function foo at 0x0000000000B91378>    #print(foo)的结果
11 <function foo at 0x0000000000B91378>    #print(f)的结果
12 foo                                     #执行f()的结果,实际就是执行foo()的结果

2、函数可以当做参数传递

 1 def foo():
 2     print("foo")
 3 print(foo)          #打印foo的内存地址空间
 4 f=foo               #把foo的内存地址空间做值赋值给f变量
 5 print(f)            #打印f,起始就是打印foo的内存地址空间
 6 f()                 #f()事实上就是执行foo函数,等同于foo()
 7 
 8 def bar(func):
 9     print(func)     #这个是打印foo()函数的内存地址
10     func()          #func是foo的内存地址,加()实际就是执行foo()函数
11     return func
12 f = bar(foo)        #这个是获取bar的返回值
13 print(f)            #打印f,就是打印bar()的返回值,就是foo()的内存地址,和print(func)相同
14 f()                 #f是bar
15 
16 def bar(func):
17     print(func)
18 
19 bar(foo())      #这个是先执行foo()行数,执行函数里的代码,先打印foo,然后把foo()的返回值作为bar()函数的实参传递给bar,foo()没有返回值,所以是None
20                 #结果就是先输出一个  "foo"     然后bar(None),把none传递给bar()函数,打印No

 

 

四、闭包:内部函数的代码包含对外部作用域的引用,但一定不是对全局作用域的引用,闭包函数一定有__closure__方法

 1 x=1
 2 def f1():
 3     x=2
 4     y=3
 5     def f2():
 6         print(x)
 7         y
 8     return f2
 9 f=f1()                  #f是f2的内存地址
10 f()                     #f()就是f2(),可以保证f2()可以在任何位置执行,而不受作用域的限制
11 print(f.__closure__)    #打印结果是元组,元组个数代表的是闭包所引用的上次函数的元素个数
12 print(f.__closure__[0]) #结果是元组,可以使用索引的方式查看
13 print(f.__closure__[0].cell_contents)   #查看指定元组所对应的应用上层参数的值
14 
15 def init(func):
16     def wrapper(*args,**kwargs):
17         res=func(*args,**kwargs)
18         return res
19     return wrapper
20     
21     

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM