十八、十九穿插python沉淀之路--嵌套、闭包、递归,三者的区别

一、嵌套函数

python允许在定义函数的时候,其函数体内又包含另外一个函数的完整定义,这就是我们通常所说的嵌套定义。为什么?因为函数是用def语句定义的,凡是其他语句可以出现的地方,def语句同样可以出现。
像这样定义在其他函数内的函数叫做内部函数,内部函数所在的函数叫做外部函数。当然,我们可以多层嵌套,这样的话,除了最外层和最内层的函数之外,其它函数既是外部函数又是内部函数。

定义:简单点儿理解就是函数(包括定义函数)内部定义了新函数,即一层套一层。

¥¥¥¥¥嵌套函数里面两个重要的概念:变量作用域   和     函数闭包

例1

 1 # 例1
 2 a = 123
 3 def outer():
 4     def inner():
 5         a = 44
 6         print(‘current a:‘,a)
 7     return inner
 8 outer()                #这一步只会访问到  outer() 这一层,而这一层什么都没有打印
 9 in0 = outer()     #通过这种方式才能访问到里层函数inner()
10 in0()
1 current a: 44

例2 :续例1 的继续深化解释

 1 # 例2
 2 name = ‘China‘
 3 def outer():
 4     name = ‘Beijing‘
 5     def middle():
 6         name = ‘海淀‘
 7         def inner():
 8             name = ‘中关村‘
 9             print(‘inner层的name:‘,name)
10         inner()
11         print(‘midlle层的name:‘,name)
12     middle()
13     print(‘outer层的name:‘,name)
14
15 outer()
16 print(‘最外层的name:‘,name)
1 inner层的name: 中关村
2 midlle层的name: 海淀
3 outer层的name: Beijing
4 最外层的name: China

之所以通过一个outerI()就打印出了所有,是因为都加了print,下一个例子将去掉print,来验证如何访问到内层的函数

例3:续例2

 1 name = ‘China‘
 2 def outer():
 3     name = ‘Beijing‘
 4     def middle():
 5         name = ‘海淀‘
 6         def inner():
 7             name = ‘中关村‘
 8             print(‘inner层的name:‘,name)
 9         inner()         #调用inner(),让其运行。
10         # print(‘midlle层的name:‘,name)
11     middle()       #调用middle() 让其运行
12     # print(‘outer层的name:‘,name)
13
14 outer()
15 print(‘最外层的name:‘,name)
1 inner层的name: 中关村
2 最外层的name: China

依结果可知:调用最外层函数,可以把最内部的inner调用打印出来。这是由于内部每一层都实现了调用。

二、闭包函数

1、何为闭包?

“官方”的解释是:所谓“闭包”,指的是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分。

通俗的讲:就是函数a的内部函数b,被函数a外部的一个变量引用的时候,就创建了一个闭包。

自解:闭包:一个函数里面嵌套一个函数的时候,调用外层函数返回里层函数本身

例1

1 def fx(x):
2     x+=1
3     def fy(y):
4         return x*y
5     return fy    #   这个语句不可以换成  fy(y)
6
7 f = fx(4)
8 n = f(4)
9 print(n)

例2

1 def fx(x):
2     x+=1
3     def fy(y):
4         print(x*y)
5     return fy    #   这个语句不可以换成  fy(y)
6
7 f = fx(4)
8 f(4)

例1、例2 的输出结果都是 20.。。print和return的差别,导致外面调用时的形式也有所不同。

2、举例解析

 1 def greeting_conf(prefix):
 2     def greeting(name):
 3         print(prefix,name)
 4     return greeting
 5
 6 mgreeting = greeting_conf(‘Good Morning‘)
 7 mgreeting(‘隔壁老王‘)
 8 mgreeting(‘对面老李‘)
 9
10 agreeting = greeting_conf(‘Good Night‘)
11 agreeting(‘隔壁老王‘)
12 agreeting(‘对面老李‘)
1 Good Morning 隔壁老王
2 Good Morning 对面老李
3 Good Night 隔壁老王
4 Good Night 对面老李

上面的代码有下面几个注意点:

  1. “greeting”函数访问了non-local的变量”prefix”,根据前面namespace的介绍,这点是完全合法的
  2. 变量”prefix”并没有随着函数的退出而销毁,反而是生命周期得到了延长

下面看看为什么变量”prefix”生命周期得到了延长?

__closure__属性

在Python中,函数对象有一个__closure__属性,我们可以通过这个属性看看闭包的一些细节

 1 def greeting_conf(prefix):
 2     def greeting(name):
 3         print(prefix,name)
 4     return greeting
 5
 6 mgreeting = greeting_conf(‘Good Morning‘)
 7 mgreeting(‘隔壁老王‘)
 8 mgreeting(‘对面老李‘)
 9 print(dir(mgreeting))
10 print(mgreeting.__closure__)
11 print(type(mgreeting.__closure__[0]))
12 print(mgreeting.__closure__[0].cell_contents)
1 Good Morning 隔壁老王
2 Good Morning 对面老李
3 [‘__annotations__‘, ‘__call__‘, ‘__class__‘, ‘__closure__‘, ‘__code__‘, ‘__defaults__‘, ‘__delattr__‘, ‘__dict__‘, ‘__dir__‘, ‘__doc__‘, ‘__eq__‘, ‘__format__‘, ‘__ge__‘, ‘__get__‘, ‘__getattribute__‘, ‘__globals__‘, ‘__gt__‘, ‘__hash__‘, ‘__init__‘, ‘__init_subclass__‘, ‘__kwdefaults__‘, ‘__le__‘, ‘__lt__‘, ‘__module__‘, ‘__name__‘, ‘__ne__‘, ‘__new__‘, ‘__qualname__‘, ‘__reduce__‘, ‘__reduce_ex__‘, ‘__repr__‘, ‘__setattr__‘, ‘__sizeof__‘, ‘__str__‘, ‘__subclasshook__‘]
4 (<cell at 0x00000173FC168468: str object at 0x00000173FC1FDAF0>,)
5 <class ‘cell‘>
6 Good Morning

通过__closure__属性看到,它对应了一个tuple,tuple的内部包含了cell类型的对象。

对于这个例子,可以得到cell的值(内容)为”Good Morning”,也就是变量”prefix”的值

从这里可以看到闭包的原理,当内嵌函数引用了包含它的函数(enclosing function)中的变量后,这些变量会被保存在enclosing function的__closure__属性中,成为enclosing function本身的一部分;也就是说,这些变量的生命周期会和enclosing function一样。

闭包和函数

闭包只是在表现形式上跟函数类似,但实际上不是函数。

 1 def greeting_conf(prefix):
 2     def greeting(name):
 3         print(prefix,name)
 4     return greeting
 5
 6 mgreeting = greeting_conf(‘Good Morning‘)
 7 print(‘function name is :‘,mgreeting.__name__)
 8 print( ‘id of mgreeting is :‘,id(mgreeting))
 9
10 agreeting = greeting_conf(‘Good Night‘)
11 print(‘function name is :‘,agreeting.__name__)
12 print( ‘id of agreeting is :‘,id(agreeting))
1 function name is : greeting
2 id of mgreeting is : 2592360143456
3 function name is : greeting
4 id of agreeting is : 2592360143592

从代码的结果中可以看到,闭包在运行时可以有多个实例,不同的引用环境(这里就是prefix变量)和相同的函数(这里就是greeting)组合可以产生不同的实例。

Python中怎么创建闭包

在Python中创建一个闭包可以归结为以下三点:

  • 闭包函数必须有内嵌函数
  • 内嵌函数需要引用该嵌套函数上一级namespace中的变量
  • 闭包函数必须返回内嵌函数

通过这三点,就可以创建一个闭包,,Python装饰器就是使用了闭包。

附注:https://www.cnblogs.com/baomanji/p/6701981.html

该链接例有 函数嵌套、函数使用、闭包的解释。

原文地址:https://www.cnblogs.com/jianguo221/p/8984618.html

时间: 2024-10-29 18:12:05

十八、十九穿插python沉淀之路--嵌套、闭包、递归,三者的区别的相关文章

十五、python沉淀之路--eval()的用法

一.eval函数 python eval() 函数的功能:将字符串str当成有效的表达式来求值并返回计算结果. 语法:eval(source[, globals[, locals]]) -> value 参数: source:一个Python表达式或函数compile()返回的代码对象 globals:可选.必须是dictionary locals:可选.任意map对象 如果提供了globals参数,那么它必须是dictionary类型:如果提供了locals参数,那么它可以是任意的map对象.

第四百四十八、九、五十天 how can I 坚持

前天回家了,家里真好,吃的挺好.现在胃口真是大增,太能吃了.在家搞了搞钱,基本也没干啥,基本都是玩了. 昨天,去交首付了,还算顺利,半天就都搞定了,从此步入房奴了,晚上吃的烧烤,挺happy也很压抑,还不是因为lcj. 今天,上午跟刘松换了合同,看了看他的样板房,确实挺不错,也挺大,比我的大不少了,虽说户型都一样.然后去找了找lcj,都不见我,也应该是情理之中的,谁让我做的那么过分呢,不知道会怎么样呢. 睡觉.

十四、python沉淀之路--文件操作

一.文件操作b模式 1. 1 # f = open('test11.py','rb',encoding='utf-8') # 这种情况会报错 2 f = open('test11.py','rb') # b 模式不能指定编码方式 3 data = f.read() 4 print('直接打印出来:',data) 5 print('解码打印\n',data.decode('utf-8')) 6 f.close() 1 直接打印出来: b'11111\r\n22222\r\n3333\r\n' 2

《浪潮之巅》十八十九章笔记

前文中,作者一直在说公司的基因,他认为每个公司的发展趋势都遵循着某个固有的规律,这个规律就是公司的基因.而有些公司,打破桎梏,用创新开拓市场,最终获得成功.诺基亚公司原本是一家经营木质品的公司,它在扩张的道路上因为铺子铺的太广,出现了严重的亏损.在新任总裁约玛·奥利拉上台后,才将移动通信做为诺基亚的核心业务.这一决定使得诺基亚由一个普通的电子公司成长为全球移动通信的领导者.诺基亚,抓住了移动通信从模拟到数字化的契机,并且在政府的大力扶植下快速发展,推翻了在模拟时代摩托罗拉制定的商业竞争规则.但是

python沉淀之路~~整型的属性

python的基础知识: 基本数据类型:int   str   list   tuple   dict   bool 一.整型的属性功能 1.工厂方法将字符串转换成整型 1 a = "1234" 2 b = int(a) 3 print(b) 4 print(type(b),b) #查看类型,同时可以返回b的值 5 # c = '124asd' 里秒你包含字符的,就不能用这个方法转换了 6 #可以通过print(type(c))来查看他的类型 运行结果 1 1234 2 <cla

二、python沉淀之路~~字符串属性(str)

1.capitalize的用法:即将输出字符串首字母大写 1 test = "heLLo" 2 v = test.capitalize() 3 print(v) 结果:Hello. 2.casefold和lower的用法以及区别 1 test = "heLLo" 2 v1 = test.casefold() 3 print(v1) 4 v2 = test.lower() 5 print(v2) 结果:hello,hello.结果相同,但是适用范围不一样.casefo

十一、python沉淀之路--map函数、filter函数、reduce函数、匿名函数、内置函数

一.map函数 1.自定义函数,实现类似于map函数的功能 1 num_l = [1,3,4,5,6,9] 2 def power(n): 3 return n ** 2 4 def map_test(func,array): 5 li0 = [] 6 for i in array: 7 p = func(i) 8 li0.append(p) 9 return li0 10 11 f = map_test(power,num_l) 运用自己定义的函数来计算 12 print(f) 13 f =

十三、python沉淀之路--文件操作

一.文件的读操作 例1 1 f = open('学习',encoding='utf-8') #首先要打开文件,不然直接读,是读不出来的 2 data = f.read() #read后的括号里不添加任何东西 3 print(data) 4 f.close() #读取完了后一定要记得关闭文件,不然内存会一直交互数据占据内存空间,而且不关闭,数据容易丢失,或被别人读取 例2:readline   readable 1 f = open('学习','r',encoding='utf-8') 2 3 p

十七、python沉淀之路--三元表达式、列表解析

一.三元表达式 1 a = '骑车' 2 3 res = '好天气' if a == '骑车' else '睡觉' 4 print(res) 1 睡觉 解析:res = '好天气'        if a == '骑车'           else '睡觉'  ,将一个句子分了三部分.简单的逻辑运算可用这种三元表达式 二.列表解析 1 gift_list = [] 2 for i in range(10): 3 gift_list.append('礼盒%s'%i) 4 print(gift_l