一 集合

1 集合定义:

1 如果花括号为空,则是字典类型 2 定义一个空集合,使用set 加小括号 使用B方式定义集合时,集合内部的数必须是可迭代对象,数值类型的不可以

其中的值必须是可迭代对象,其中的元素必须是可hash,其中s=set([1,2,3,4,5,6]) 的含义是其是列表,其列表是可迭代,且其获取到的是其中的元素,不是列表。

2 set 和线性结构

线性结构的查询时间复杂度是O(n),即随着数据规模的增大而增加耗时

set、dict 等结构,内部使用hash值做为key,时间复杂度可以做到O(1),查询时间和数据规模无关

可hash的对象 数值类型 int float complex 布尔型 True False 字符串 string bytes tuple None 以上都是不可变类型,称为可哈西类型,hashable set 的元素必须是可hash的。

2 集合的简单应用

实现对集合内元素的去重操作,此操作可应用于对列表的去重 1 使用集合对列表进行去重操作

2 使用字典的键不重复性对列表进行去重

3集合的增删改查

1 集合的增:

A add 实现对非可变类型数据的添加操作(除列表,字典)

B update 实现对可迭代对象的加入操作(数值类型则不能加入其中)

2 删

A pop()支持对集合的无序删除操作

B remove 支持对集合的指定元素的删除工作,若不存在,则报错

C discard 删除集合中指定元素,如果不存在,则无反应

D clear 清空集合

例题应用:

要求输入一个数,使其成为1-1000之间产生随机数的个数的总和个数,并对这些数进行排序(有小到大)

1
[root@www ~]# cat a.py

#!/usr/bin/env python 
#coding=utf-8
import random   #导入该模块,用于生成1到1000的随机数
l1=[]
s=set()
N=input("请输入数字总和N:")
for i in range(N):  #进行循环的总数
	N1=random.randint(1,1000)   # 生成1-1000内的随机数N个 
	s.add(N1)
	l1=list(s)
	l1.sort() #使用列表的内置方法进行排序
print l1

2
[root@www ~]# cat a.py

#!/usr/bin/env python 
#coding=utf-8
import random
l1=[]
s=set()
N=input("请输入数字总和N:")
for i in range(N):
	N1=random.randint(1,1000)
	s.add(N1)
	l1=list(s)
print sorted(l1)  使用内置函数进行排序

3 查(关系测试)

1 交集 (输出两个集合中共有的元素)

2 并集(输出列个集合中所有存在的元素)

3 差集(输出第一个集合中与第二个集合不同的元素)

4 对等差分 (输出两个集合中各不存在但对方存在的元素)

集合关系判断(子集,父集)

4 练习

随机产生2个各10个数字的列表,要求如下: 1 每个数字取值范围是[10,20] 2 统计20个数字中,一共多少个不同的数字 3 2组中,不重复的数字有几个,分别是多少 4 2 组中,重复的数字有几个,分别是什么

import  random
l1=[]
l2=[]
for i in range(10):  # 生成10个随机数,其取值范围是10,20
    l1.append(random.randint(10,20))
    l2.append(random.randint(10,20))

print  ("不同数字个数为{},不重复数字有{}个,分别是{},重复数字为{},共{}个".format(set(set(l1)|set(l2)),(len(set(l1)^set(l2))),(set(l1)^set(l2)),(set(l1)&set(l2)),len(set(l1)&set(l2))))

# 不重复表示是对等差集

二 总结:

1 可变数据类型:列表,字典,集合 2 不可变数据类型:数值类型,元祖,字符串

可变数据类型实现某个功能,直接改变可变的数据 不可变数据类型实现某些功能,需要将结果赋值给另一个变量

可迭代数据类型(能实现for 循环):str list tuple dict set 不可迭代数据类型:数值类型

是否支持索引,切片,链接,重复特性 有序的数据类型:str list tuple 无序的数据类型:dict set

二 解析式

1 列表解析 list comprehension

1 概述

列表解析式是一种语法糖 编译器会优化,不会因为简写而影响效率,反而因优化而提高了效率 减少程序员工作量,减少出错 简化了代码,但可读性增强

2 语法

语法: [ 返回值 for 元素 in 可迭代对象 if 条件] 使用中括号[],内部是for循环,if 条件语句可选 返回一个新的列表

3 进阶

[item  for  item  in  iterable  if  cond1  if  cond2] #等价于

ret=[]
for item  in   iterable:
	if cond1:
		if cond2:
			ret.append(item)

[ (i*j)  for i in  iterable1  for  j in iterable2]  #等价于 
ret=[]
for  i in  iterable1:
	for j in iterable2:
		ret.append(i*j)

4 练习

1 返回1-10平方的列表

In [1]: [pow(i,2)  for i in range(1,11)]                                              
Out[1]: [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

2 有一个列表lst=[1,4,9,16,2,5,10,15],生成一个新列表,要求新列表的元素是lst相邻2项的和

In [15]: lst=[1,4,9,16,2,5,10,15]                                                     
In [16]: [lst[i]+lst[i+1]  for i in  range(len(lst)-1)]                               
Out[16]: [5, 13, 25, 18, 7, 15, 25]

3 打印九九乘法表

In [5]: [print ("{}*{}={:<3}{}".format(j,i,j*i,'\n' if  i==j  else " "),end="")  for i
   ...:  in range(1,10)  for j in range(1,i+1)]                                       
1*1=1  
1*2=2   2*2=4  
1*3=3   2*3=6   3*3=9  
1*4=4   2*4=8   3*4=12  4*4=16 
1*5=5   2*5=10  3*5=15  4*5=20  5*5=25 
1*6=6   2*6=12  3*6=18  4*6=24  5*6=30  6*6=36 
1*7=7   2*7=14  3*7=21  4*7=28  5*7=35  6*7=42  7*7=49 
1*8=8   2*8=16  3*8=24  4*8=32  5*8=40  6*8=48  7*8=56  8*8=64 
1*9=9   2*9=18  3*9=27  4*9=36  5*9=45  6*9=54  7*9=63  8*9=72  9*9=81 

4 "0001.abcdefghij" 是ID格式,要求ID格式是以点好分割,左边是4位从1开始的整数,右边是10位随机小写英文字母,请以此生成前100个id的列表。

In [1]: import  random                                                                

In [2]: import  string                                                                

In [3]: ["{:04}.{}".format(i,"".join(random.sample(string.ascii_lowercase,10)))  for i
   ...:  in range(1,101)]                                                             
Out[3]: 
['0001.wzmedfgach',
 '0002.teandiuzbq',
 '0003.mgvprdwtbz',
 '0004.hdcjryliun',
 '0005.rkbdanezip',
 '0006.yabquwrjfm',
 '0007.xhriugvyfl',
 '0008.yjosmvrxuf',
 '0009.oepwvfyzxj',
 '0010.hzcigsnqkw',
 '0011.kygrvidtla',
 '0012.tpsjmzdvca',
 '0013.mhwixqprdy',
 '0014.rmgvxubklj',
 '0015.crtwsnpubg',
 '0016.tpcmeoxgzf',
 '0017.ulovngcyki',
 '0018.njiagycwvd',
 '0019.sbjcutgvxr',
 '0020.cazqujrdtk',
 '0021.fnteuvaozd',
 '0022.zlsiqxwcoa',
 '0023.lxzojifvqb',
 '0024.zpudanijfm',
 '0025.zdjsawlurp',
 '0026.viqekcsfyr',
 '0027.psgitcvwlq',
 '0028.xnwyjvstdp',
 '0029.jdnbazgrxo',
 '0030.ifshwdnmpy',
 '0031.dfchqxuvbj',
 '0032.jdkehycosl',
 '0033.bjhnofwxgd',
 '0034.kbucwogptl',
 '0035.ctosfdqaie',
 '0036.plcgqbvnzr',
 '0037.lbygqswtjo',
 '0038.clgqzrmfpe',
 '0039.xynsopwfld',
 '0040.lzqxkeycjg',
 '0041.azexdhpwqf',
 '0042.sqxubrijdo',
 '0043.xrdbtspiac',
 '0044.unvjbchdsi',
 '0045.xwfrtduobv',
 '0046.fmjgwnahyz',
 '0047.qjcvluokpw',
 '0048.depfjnyviw',
 '0049.fyhvctzneb',
 '0050.grblkwfioq',
 '0051.mvlfdaengp',
 '0052.bxlnkfuoqh',
 '0053.kicejmfqxn',
 '0054.qxzpjolvkw',
 '0055.sptuwycjrx',
 '0056.bhljztgdfi',
 '0057.htrjiqxfdv',
 '0058.hfqdnurxbp',
 '0059.kygirhzjbe',
 '0060.gkilhandxs',
 '0061.okbmcgzqwv',
 '0062.lkujswvyra',
 '0063.jeqvbuczap',
 '0064.asqfmkrjpn',
 '0065.tdaufvkrie',
 '0066.axlgjumfbe',
 '0067.kgwvhlodrt',
 '0068.psvwahceiz',
 '0069.srtufplwaj',
 '0070.lvhouijnxw',
 '0071.ofkmaiugqc',
 '0072.awfpcyogie',
 '0073.agckzpbxyf',
 '0074.zpmsajbxld',
 '0075.jskbpqzxcv',
 '0076.cgevhqjkfr',
 '0077.uwirenmlhk',
 '0078.gnbozqvmif',
 '0079.hbjtcrpxds',
 '0080.qkvwluazfm',
 '0081.dileuwsmfh',
 '0082.djmgswhytp',
 '0083.pictkgmefh',
 '0084.aqijzmpkny',
 '0085.bwmgudzclt',
 '0086.omzwylnbxp',
 '0087.nhvgfbrdyq',
 '0088.sdaiwoqzht',
 '0089.xiqetyjprf',
 '0090.qaidkozlmg',
 '0091.xwarkuylfo',
 '0092.dqmkpobfia',
 '0093.owqausrpnb',
 '0094.gxazkslifh',
 '0095.dtxfepmylv',
 '0096.olejwvhsfp',
 '0097.excdapiyvb',
 '0098.zoq***ytbu',
 '0099.euhjblfqkn',
 '0100.pzhejmwybg']

2 集合解析式

1 语法

	{ 返回值   for  元素   In   可迭代对象 if 条件}
	立即返回一个集合 

2 练习

返回一个1到10的平方的集合

In [1]: {pow(i,2)  for i in range(1,11)}                                              
Out[1]: {1, 4, 9, 16, 25, 36, 49, 64, 81, 100}

3 字典解析式

1 语法

{返回值   for  元素   In   可迭代对象   if  条件 }
使用key,value 形式接受
立即返回一个字典

2 练习

In [2]: {str(i):i  for i in range(10)}                                                
Out[2]: 
{'0': 0,
 '1': 1,
 '2': 2,
 '3': 3,
 '4': 4,
 '5': 5,
 '6': 6,
 '7': 7,
 '8': 8,
 '9': 9}
 
 In [3]: {str(i):[i,i+1]  for i in range(10)}                                          
Out[3]: 
{'0': [0, 1],
 '1': [1, 2],
 '2': [2, 3],
 '3': [3, 4],
 '4': [4, 5],
 '5': [5, 6],
 '6': [6, 7],
 '7': [7, 8],
 '8': [8, 9],
 '9': [9, 10]}
 
 In [4]: {str(i):[j]  for i in range(10) for j in range(10,21)}        # 此处会覆盖,因为前面一直在赋值。                  
Out[4]: 
{'0': [20],
 '1': [20],
 '2': [20],
 '3': [20],
 '4': [20],
 '5': [20],
 '6': [20],
 '7': [20],
 '8': [20],
 '9': [20]}


三 生成器表达式

1 和列表解析式的区别

生成器表达式是按需计算(或成为惰性求值,延迟计算),需要的时候才计算值 列表解析式是立即返回值,生成器从前到后走完一遍后,不能回头。列表解析从签到后走完一边后可以回头迭代。 生成器 是可迭代对象,是迭代器 迭代器只能使用一次,但可迭代对象不能使用next()方法 能用next,必须是迭代器, 可迭代对象不一定是迭代器,但迭代器一定是可迭代对象

2 语法

(返回值 for 元素 in 可迭代对象 if 条件) 列表解析式中括号换成了小括号 返回一个生成器

3 练习

由上述可知,生成器只能迭代一次,而列表解析式可以重复迭代

In [6]: it=("{}".format(i+1)  for i in range(2))                                      

In [7]: next(it)                                                                      
Out[7]: '1'

In [8]: next(it)                                                                      
Out[8]: '2'

In [10]: it=("{}".format(i+1)  for i in range(2))                                     

In [11]: for i in it: 
    ...:     print (i) 
    ...:                                                                              
1
2

四 函数

1 无参数的函数

函数的定义: def 函数名(): 函数体

函数的调用: 函数名()

定义函数时,函数不执行,调用函数时,函数才执行

2 有参数的函数

1 形参

在def 函数定义时使用的参数称为形式参数,不具备实际的意义, def a1(x,y): ....: print x+y

此时的x,y被称为形式参数 形参的分类

A 必须参数 def a1(x,y): ....: print x+y


B 默认参数

In [59]: def a4(x,y=1): #y=1 用于当只传入一个参数时,此y=1则会发生作用,若传入两个参数,则失效 ....: print x,y ....:

In [60]: a4(1) 1 1

In [61]: a4(1,2) 1 2


C 可变参数

In [38]: def a2(*x): 可以同时传输多个参数,其产生的结果是一个元祖 ....: print x ....:

In [39]: a2(1,2,3,4,5,6) (1, 2, 3, 4, 5, 6)

a2([1,2,3,4,5]) ([1, 2, 3, 4, 5],)


D 关键字参数:

In [57]: def a3(**x): ....: print x #其返回值是一个字典 ....:

In [58]: a3(a=1,b=2,c=3) {'a': 1, 'c': 3, 'b': 2}

函数定义时,若有多种类型的参数需要定义,则必须要遵循:必须参数--默认参数--可变参数--关键字参数

2 实参

在调用函数时传入函数体内部的参数称为实参,有实际的效果的参数 In [35]: a1(1,2) 3 In [36]: a=1;b=3 In [37]: a1(a,b) 4 此时的1,2 和 a,b 都是实参

应用,用于数之和 In [41]: def a2(*x): ....: sum=0 ....: for i in x: ....: sum+=i ....: print sum ....:

In [42]: a2(1,2,3,4,5,6,7,8,9) 45

3返回值

函数中没有return时,默认返回None

1 返回多个值

#!/usr/bin/env python 
#coding=utf-8
def a1(\*args):
    '''
返回最大值和最小值
:param args: 要求输入多个数作比较
:return: 返回最大值和最小值
    '''
return  max(args) ,min(args)
print a1(1,2,3,4,10,20,100)

4 函数的变量作用域

作用域 : 一个标识符的可见范围,这就是标识符的作用域,一般常说的是变量的作用域。 全局作用域: 在整个程序运行环境中均可见

局部作用域: 在函数/类等内部可见 局部变量使用范围不能超过其所在的局部作用域

	In [1]: def x(): 
   ...:     a=1 
   ...:                                                                                                         

In [2]: def y(): 
   ...:     print (a) 
   ...:                                                                                                         

In [3]: print (a)     #在函数x中定义的局部变量在外部不能调用                                                                                            

NameError                                 Traceback (most recent call last)
<ipython-input-3-cb9bacd097d9> in <module>
----> 1 print (a)

NameError: name 'a' is not defined

In [4]: y()                         # 在函数x中定义的局部变量在函数y中不能被调用                                                                              
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-4-6fa9c8f97a35> in <module>
----> 1 y()

<ipython-input-2-455e1fcd2512> in y()
      1 def y():
----> 2     print (a)
      3 

NameError: name 'a' is not defined
	```


**重点 
**

In [1]: x=5

In [2]: def a(): ...: y= x+1
...: print (x) ...:

In [3]: a()
5

In [4]: def b(): ...: x=x+1 ...: print (x) ...:

In [5]: b
Out[5]: <function main.b()>

In [6]: b()

UnboundLocalError Traceback (most recent call last) <ipython-input-6-3bf86fc5afda> in <module> ----> 1 b()

<ipython-input-4-b0b3ab5ae26b> in b() 1 def b(): ----> 2 x=x+1 3 print (x) 4

UnboundLocalError: local variable 'x' referenced before assignment



> x+=1  可以转换为x=x+1,  x= 相当于定义了新的变量x,其相当于赋值前引用变量。一般是先赋值,后引用。


解决方式
1 定义全局变量

x=5 In [7]: def b(): ...: global x # 全局变量中必须要有,否则出错 ...: x=x+1 ...: print (x) ...:

In [8]: b()
6


In [1]: x=5

In [2]: def a(): ...: global x ...: x=10 ...: x+=1 ...: print (x) ...:

In [3]: a()
11

In [4]: print (x)
11


> 此时内部的x=10相当于覆盖了外部的x=5,因此其值会变成此种情况


global 关键字必须要先声明,再使用

#!/usr/bin/env python #coding=utf-8

x=1 def a1(x): x=2 print x


> print x  其结果是x=1
> a1(x)  其结果是x=2 ,因为在调用函数内部时,此x=2是局部变量,其优先级高于x=1

global总结:

> x+=1 这中特殊形式产生的原因是先引用后赋值,而python中动态语言是赋值之后才有意义,才能被引用,解决方式有两种,第一种是直接在内部定义覆盖外部,第二种是使用global 进行声明,让其去外部寻找该变量然后完成运算,
> 
> 内部作用域赋值全局作用域的变量,其会覆盖全局变量在本函数内的变量值,而使用global 声明其为全局的,一旦内部进行重新赋值,则该值成为全局变量的值。
> 

-----


global使用规则:

> 1 外部作用域变量会在内部作用域可见,但也不要在这个内部的局部作用域中直接使用,因为函数的目的就是封装,而应该尽量与外界隔离。
> 2 如果函数需要使用外部全局变量,则建议使用形参传递参数解决,尽量不适用定义。
> 3 不建议使用global 

## 5  默认值作用域 
### 1 实例
实例1 

In [1]: def a(x=1): ...: print (x) ...:

In [2]: a()
1

In [3]: a()
1

In [4]: print (x)

NameError Traceback (most recent call last) <ipython-input-4-606ad02f996c> in <module> ----> 1 print (x)

NameError: name 'x' is not defined

此处因为x是局部变量,及默认形式参数是局部变量

实例2 

In [1]: def a(x=[]): ...: x.append(1) ...: print (x) ...:

In [2]: a()
[1]

In [3]: a()
[1, 1]

In [4]: a()
[1, 1, 1]


> 上述实例中,原本的结果应该是每次调用其值都是一个列表,因为函数在调用完成后便会自动消失,但次上述出问题的原因是其默认作用域的原因,因为函数也是对象,python将函数的默认值放置在了属性中,这个属性就伴随着函数对象的整个生命周期,a.__defaults__表示了函数对象的属性,及保存其默认属性值的位置,

实例3 

In [1]: def a(x=[],y=1,z=2): ...: x.append(1) ...: print (x) ...:

In [2]: print (a(),id(a))
[1] None 139758163502216

In [3]: print (a.defaults)
([1], 1, 2)

In [4]: print (a(),id(a))
[1, 1] None 139758163502216

In [5]: print (a.defaults)
([1, 1], 1, 2)

上述结果可得,其函数的地址没变,及函数对象没变,调用属性__defaults__使用元祖保存其default默认值,但元祖中有列表,其元祖中的列表是可变的,因此其会发生变化 

实例4  

In [1]: def a(x,y=1,z=2): ...: y=2 ...: z=3 ...: print (x,y,z) ...:

In [2]: print (a.defaults)
(1, 2)

In [3]: a(10)
10 2 3

In [4]: print (a.defaults)
(1, 2)


由此可知: 可变类型默认值,如果使用默认值,则就可能修改这个默认值,某些时候是不需要的,解决方式如下:

1  影子拷贝 

In [1]: def a(x=[],y=1,z=2): ...: print (id(x)) ...: x=x[:] #使用影子拷贝,其返回的是一个全新的列表,和切片一样,其比较浪费内存资源。 ...: print (id(x)) ...: x.append(1) ...: print (x) ...:

In [2]: a()
140285447782088 140285501277768 [1]

In [3]: print (a.defaults)
([], 1, 2)

In [4]: a([10])
140285501944072 140285481599304 [10, 1]

In [5]: print (a.defaults)
([], 1, 2)

In [6]: a([10,20])
140285447692488 140285447654920 [10, 20, 1]

In [7]: print (a.defaults)
([], 1, 2)

2  使用不可变类型进行处理

In [1]: def a(x=None,y=1,z=2): ...: if x is None: ...: x=[] ...: x.append(1) ...: print (x) ...:

In [2]: a()
[1]

In [3]: a()
[1]

In [4]: a.defaults
Out[4]: (None, 1, 2)

In [5]: a([10]) # 此处只能传入列表
[10, 1]

In [6]: a.defaults
Out[6]: (None, 1, 2)

> 如果是传入一个缺省值则创建一个列表,如果传入一个列表,则修改此列表,此种方式常用,此是在原有列表的基础上修改,较影子拷贝相比更加节省资源。

### 6 函数销毁 
1 全局函数销毁
		重新定义同名函数
		

def foo(xyz=[],u='abc',z=123): xyz.append(1) return xyz print (foo(),id(foo),foo.defaults)

def foo(xyz=[]): # 当第二个定义后,第一个函数将会漂浮在哪里没人用了,直到垃圾回收器对其进行相关的回收 xyz.append(1) return xyz print (foo(),id(foo),foo.defaults)

结果如下 

![](https://s1.51cto.com/images/blog/201905/13/240a53fe15bdaedc7398d2e106e8022a.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_30,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=)
Del 语句删除函数对象

def foo(xyz=[],u='abc',z=123): xyz.append(1) return xyz print (foo(),id(foo),foo.defaults) del foo # 使用del删除函数的地址引用,当其地址引用为0时,其会被垃圾回收器回收 print (foo(),id(foo),foo.defaults)

结果如下 

![](https://s1.51cto.com/images/blog/201905/13/e91d7eedc31cd81032ab1ffd6ca990eb.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_30,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=)
程序结束时 

2局部函数销毁
重新在上级作用域中定义同名函数

def foo(xyz=[],u='abc',z=123): xyz.append(1) def foo1(): pass print (id(foo1)) def foo1(u='acd'): # 重新定义嵌套函数 print (xyz) print (id(foo1)) return foo1

bar=foo() print (id(bar),foo.defaults) # 其中id(bar)指的是foo1的函数内存位置,其默认使用下面的函数

结果如下:
![](https://s1.51cto.com/images/blog/201905/13/fef33e8c386573b91fb714bc50f3fbb7.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_30,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=)

del 语句删除函数对象

def foo(xyz=[],u='abc',z=123): xyz.append(1) def foo1(): pass print (id(foo1)) return foo1 bar=foo() print (id(bar),foo.defaults) # 其中id(bar)指的是foo1的函数内存位置 del bar

prnt (id(bar),foo.defaults)

结果如下
![](https://s1.51cto.com/images/blog/201905/13/6765135f16ed5475b0502ac07388209f.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_30,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=)
上级作用域销毁时
		
### 7  递归函数
1  函数执行流程

def foo(b,b1=3): print ("foo called",b,b1)

def foo1(c): foo2(c) print ("foo1 called",c)

def foo2(d): print ("foo2 called",d)

def main(): print ("main called") # 进入上述LEGB进行寻找,最后找到build-in后调用print 返回上述结果,其会将字面常量压到栈中, # 内存中是分堆和栈的,栈是函数的,是一个先进后出的,后进先出的,main函数的栈直接被压在了main之上,当print执行后 # 其将被弹出,弹出后,main函数中的其他内容将会被继续执行 foo(100,101) #python中没有常量,但其有字面常量,只要敢定义,就敢变。将foo进行压栈,将常量依次压栈,若有变量,则进行 #load,调用函数foo,创建栈帧,为此函数在栈中创建一段(栈帧),print压栈,然后调用,后弹出。 foo1(200) #下面同上 print ("main ending") main()


2  递归 recursion 
> 函数直接或间接调用自身就是递归
> 递归需要有边界条件,递归前进段,递归返回段
> 递归一定要有边界条件
> 当边界条件不满足时,递归前进
> 当边界条件满足时,递归返回 


实例 :
1 斐波那契数列

def x(a): if a<2: return a else: return x(a-1)+x(a-2) # 下一个数等于前两个之和

for i in range(1,10): #通过for不断生成下一个数 print (x(i))

结果如下 
![](https://s1.51cto.com/images/blog/201905/13/2d140c7afcb0d6470944cd4fd17d6f4e.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_30,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=)
2 阶乘

def x(a): if a==1: return a else: return a*x(a-1)

x(10)

结果如下 
![](https://s1.51cto.com/images/blog/201905/13/d1ffa78a4da9f3c046c227dc8c57c570.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_30,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=)

3  将一个数逆序放入列表中
1234  -> [4,3,2,1]
> 核心思想,使用数字的处理方式将其每一位截取出来,然后进行相关的操作即可。

def x(n,l1=[]): if n<10: l1.append(n) return l1 # 最终返回值 else: l1.append(n%10) return x(n//10,l1) #调用函数递归 print (x(1234))


结果如下
![](https://s1.51cto.com/images/blog/201905/13/71491fae3dc96d8bf165e828387e79df.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_30,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=)

4 字典的扁平化
```
def  d1(c1,c2=dict(),k=""): # 此处定义的空字典用于接受字典,此处的k用于接受字典的键(key)
    if  type(c1)==dict:
        for i,j in c1.items():  # 通过此处判断字典的值,若其值为字典类型,则继续进行递归操作,直到其值不为字典时为止,
            if  type(j)==dict:
                d1(j,c2,k+i)#此处的k+i及就是对两个字符串进行组合,而后通过点号将其分离
            else:
                c2[".".join(k+i)]=j
    return   c2
print  (d1({'a': {'b': 1, 'c':{'i':10}}, 'd': {'e': 3, 'f': {'g':{'h':5}}}}))
```
结果如下

![](https://s1.51cto.com/images/blog/201905/21/442ff3bb649677add1dfa64f7dee5d07.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_30,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=)

### 8 总结 
> 名称空间:一个变量所能够生效的作用域
> 本地作用域:只能在函数内部使用
> 模块定义:全局作用域
> 函数定义:本地作用域
> 变量名解析:LEGB 原则:
> 变量名引用分三个作用域进行: 首先是本地。之后是函数内,接着是全局,最后是内置
> Python 创建、改变或查找变量名都是在名称空间中进行
>  在代码中变量名被赋值的位置决定了其能被访问到的返回
>  函数定义了本地作用域,而模块定义了全局作用域
>  每个模块都是一个全局作用域,因此,全局作用域的范围仅限于单个程序文件
>  每次对函数的调用都会创建一个人新的本地作用域,赋值的变量除非声明为全局变量,否则均为本地变量
>  所有的变量都可以归纳为本地、全局或内置的(由_builtin_模块所提供的)