一 集合
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,20l1.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 1In [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 definedIn [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()
5In [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+13 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()
11In [4]: print (x)
11
此时内部的x=10相当于覆盖了外部的x=5,因此其值会变成此种情况
global 关键字必须要先声明,再使用
#!/usr/bin/env python
#coding=utf-8x=1
def a1(x):x=2print 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()
1In [3]: a()
1In [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 139758163502216In [3]: print (a.__defaults__)
([1], 1, 2)In [4]: print (a(),id(a))
[1, 1]
None 139758163502216In [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 3In [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__)
结果如下
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__)
结果如下
程序结束时
2局部函数销毁
重新在上级作用域中定义同名函数
def foo(xyz=[],u='abc',z=123):xyz.append(1)def foo1():passprint (id(foo1))def foo1(u='acd'): # 重新定义嵌套函数print (xyz)print (id(foo1))return foo1bar=foo()
print (id(bar),foo.__defaults__) # 其中id(bar)指的是foo1的函数内存位置,其默认使用下面的函数
结果如下:
del 语句删除函数对象
def foo(xyz=[],u='abc',z=123):xyz.append(1)def foo1():passprint (id(foo1))return foo1
bar=foo()
print (id(bar),foo.__defaults__) # 其中id(bar)指的是foo1的函数内存位置
del bar prnt (id(bar),foo.__defaults__)
结果如下
上级作用域销毁时
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 aelse:return x(a-1)+x(a-2) # 下一个数等于前两个之和for i in range(1,10): #通过for不断生成下一个数print (x(i))
结果如下
2 阶乘
def x(a):if a==1:return aelse:return a*x(a-1)x(10)
结果如下
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))
结果如下
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)]=jreturn c2
print (d1({'a': {'b': 1, 'c':{'i':10}}, 'd': {'e': 3, 'f': {'g':{'h':5}}}}))
结果如下
8 总结
名称空间:一个变量所能够生效的作用域
本地作用域:只能在函数内部使用
模块定义:全局作用域
函数定义:本地作用域
变量名解析:LEGB 原则:
变量名引用分三个作用域进行: 首先是本地。之后是函数内,接着是全局,最后是内置
Python 创建、改变或查找变量名都是在名称空间中进行
在代码中变量名被赋值的位置决定了其能被访问到的返回
函数定义了本地作用域,而模块定义了全局作用域
每个模块都是一个全局作用域,因此,全局作用域的范围仅限于单个程序文件
每次对函数的调用都会创建一个人新的本地作用域,赋值的变量除非声明为全局变量,否则均为本地变量
所有的变量都可以归纳为本地、全局或内置的(由_builtin_模块所提供的)
转载于:https://blog.51cto.com/11233559/2059485