python2和python3 的差别
python2:
print('abc') print 'abc' 两种方式都是都可以
range() xrange() 生成器
raw_input() 用户交互
python3:
print('abc')
range() 生成器
input() 用户交互
其他知识:
= 赋值
== 比较值是否相等
is 比较,比较的是内存地址
id(内容) 打印该内容的内存地址
小数据池:为了节省内存空间,数字和字符串在小范围内可共用一个对象
1,数字,字符串有小数据池
数字小数据池的范围 -5 -- 256
字符串:1,不能有特殊字符
2,s*20 还是同一个地址,s*21以后都是两个地址
i1 = 6
i2 = 6
print(id(i1),id(i2)) #两个id内存地址一样,属于小数据池
i1 = 300
i2 = 300
print(id(i1),id(i2)) #两个id内存地址不一样,不属于小数据池
2,剩下的 list dict tuple set 不具有小数据池
l1 = [1]
l2 = [1]
print(l1 is l2) ------>False
深浅copy
a = [11,22] b = [33,44] c=[a,b]
d = c:是将这个新的变量指向之前那个数据的内存地址,d,c的d is c --> Ture,内存地址一样,只是指向之前的内存地址。
e = copy.copy(c) # e和d的内存地址不一样,copy是开辟了一个新空间,但是e[0] ,e[1]的内存地址和c[0],c[1]一样,所以copy的方式只是开辟了一个新内存地址,里面的元素任然是指向之前的元素,就会随着之前的元素改变而改变,即为浅copy
f = copy.deepcopy(c) # f和c的内存地址不一样,f[0],f[1]和c[0],c[1]的内存地址也不一样,完全复制了一份数据,独立于之前的元素,即为深copy。
浅copy,只对表层数据起作用,对嵌套的数据不起作,会随着嵌套内数据的改变而改变
#没有嵌套的列表 # l1 = [1,2,3] # l2 = l1.copy() # print(l1,l2) # print(id(l1),id(l2)) # l1和l2的内存地址不一样 # l1.append('a') # print(l1,l2) #对l1操作不会影响l2的值 #嵌套的列表 # l1 = [1,2,[4,5,6],3] # l2 = l1.copy() # # print(l1,id(l1)) #1812439743240 # print(l2,id(l2)) # 1812435321608 l1和l2的内存地址不一样 # l1.append('a') # print(l1) #[1, 2, [4, 5, 6], 3, 'a'] # print(l2) #[1, 2, [4, 5, 6], 3] # l1[2].append('a') # print(l1) #[1, 2, [4, 5, 6, 'a'], 3] # print(l2) #[1, 2, [4, 5, 6, 'a'], 3] # print(id(l1[2])) #2236254917896 # print(id(l2[2])) #2236254917896 l1[2],l2[2]的内存地址相同 #对列表l1里面嵌套的列表的数值进行操作会改变l2的值
深copy,对于copy出来的内容完全独立,是一个不受父本影响的新的数据容器
# import copy # l1 = [1,2,[4,5,6],3] # l2 = copy.deepcopy(l1) # print(l1,id(l1)) #[1, 2, [4, 5, 6], 3] id: 1741159826824 # print(l2,id(l2)) #[1, 2, [4, 5, 6], 3] id:1741159827336 # l1[2].append('a') # print(l1) #[1, 2, [4, 5, 6, 'a'], 3] # print(l2) #[1, 2, [4, 5, 6], 3] 深copy不会在受影响 # l1 = [1,[1],2,3,4] # l2 = l1[:] #为浅copy # print(l2) # l1[1].append('a') # print(l1) #[1, [1, 'a'], 2, 3, 4] # print(l2) #[1, [1, 'a'], 2, 3, 4]
闭包:如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包
a = 1 def outer(a): def inner(): print(a) inner() outer(a)
装饰器:一个函数需要扩展功能,但要遵循封闭开放原则,不能对原函数进行修改,装饰器的存在就是为了在不修改函数的调用方式和代码。就是对函数的装饰,使其在不被修改的原则下有新功能
def wapper(func): #装饰器 def inner(*args,**kwargs): #可以接受任何的参数 res = func(*args,**kwargs) return res #返回的是my_sum的结果 return inner #返回inner,切记不可写inner() @wapper #语法糖 相当于 my_sum = my_sum(1,2) def my_sum(a,b): #被装饰函数 sum1 = 0 sum1= a + b return sum1 sum = my_sum(1,2) #inner(1,2) print(sum)
装饰器固定模式:
def wrapper(func): #func == qqxing def inner(*args,**kwargs): ret = func(*args,**kwargs) #被装饰的函数 return ret return inner @wrapper #qqxing = wrapper(qqxing) def qqxing(): print(123) ret = qqxing()
装饰器的进阶:
带参数的装饰器:
#带参数的装饰器需要嵌套三个函数,外层函数可以用来控制是否需要执行装饰器装饰函数的功能 falg = True #控制是否执行装饰器,False表示不执行 def log_sum(falg): def wrappers_sum(func): global falg def inner(*args,**kwargs): global falg if falg: print('----------------') ret = func(*args,**kwargs) print('----------------') #falg = False #多个函数用装饰器的时候,只让其使用一次,再一次功能中登陆账号后,后面再调其他函数时就不需要重新登陆 return ret else: ret = func(*args,**kwargs) return ret return inner return wrappers_sum @log_sum(falg) #log_sum(falg) --->wrappers_sum 先执行log_sum(falg) 得到@wrappers_sum 就是一个装饰器 def my_sum(a,b): sum = 0 sum = a + b print('good') return sum print(my_sum(1,2)) @log_sum(falg) def good(): print('sss') good()
多个装饰器装饰一个函数:
#多个装饰器装饰一个函数 # def wrapper1(func): # def inner1(): # print('wrapper1 ,before func') # ret = func() # print('wrapper1 ,after func') # return ret # return inner1 # def wrapper2(func): # def inner2(): # print('wrapper2 ,before func') # ret = func() # print('wrapper2 ,after func') # return ret # return inner2 # def wrapper3(func): # def inner3(): # print('wrapper3 ,before func') # ret = func() # print('wrapper3 ,after func') # return ret # return inner3 # @wrapper3 # @wrapper2 # @wrapper1 # def f(): # print('in f') # return '哈哈哈' # print(f())
打印结果:
wrapper3 ,before func wrapper2 ,before func wrapper1 ,before func in f wrapper1 ,after func wrapper2 ,after func wrapper3 ,after func 哈哈哈
迭代器:
可迭代对象可以使用双下函数来变成一个迭代器。迭代器的优点是可以一个一个的拿出容器中的数据,且可以节约内存空间
可迭代对象有 list tuple str set dict
list = [1,2,3,4] list1 = list.__iter__() #将可迭代对象变为迭代器 print(list1.__next__()) #一个一个去出容器中的数值
迭代对象中有 __iter__函数
迭代器中有__iter__和__next__函数
可以使用dir(数据类型)来看它有哪些双下划函数 如里面有__iter__函数则说明该i数据类型是可迭代对象
可以使用dir(数据类型)来看它有哪些双下划函数 如里面有__iter__和__next__函数则说明该i数据类型是可迭代器
可迭代的对象就可以被for循环来遍历
生成器:
本质:就是一个迭代器
优点:1.节省内存空间
2.好操作,可以一个一个取值,不重复取值
生成器函数:只要有yield关键字的函数就是一个函数表达式
def good(): #good()为一个生成器函数 yeild 'good' #yield 返回值,与return一样,但是不会终止函数
g = good() #调用生成器函数 ,返回一个生成器(g)
生成器取值:
print(g.__next__()) #一个一个的取出生成器的值,每次生成一个不占内存,且取过的值不再取不重复,如果取完了里面的值再次取会报错
for i in g:
print(i) #一次性取出全部的值
a = list(g) #类型强制转换,将生成器中的值全部转换为列表元素,一次取完
生成器表达式
列表推导式:
[每一个元素或者是和元素相关的操作 for 元素 in 可迭代数据类型] #遍历之后挨个处理
[满足条件的元素相关的操作 for 元素 in 可迭代数据类型 if 元素相关的条件] #筛选功能
list1 = [i for i in range(10)] #列表推导式,操作方便 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
list = (i for i in range(10) if i>=5) #list为列表
print(list) #[5,6,7,8,9]
生成器表达式
(每一个元素或者是和元素相关的操作 for 元素 in 可迭代数据类型) #遍历之后挨个处理
(满足条件的元素相关的操作 for 元素 in 可迭代数据类型 if 元素相关的条件) #筛选功能
list = (i for i in range(10) if i>=5) #list为生成器 list.__next__() #5 list.__next__() #6 list.__next__() #7
生成器的进阶: send的取值作用与__next__()一样,只是在获取下一个值的时候,给上一yield的位置传递一个数据
***不能直接再开头使用send取值,因为没有yield可以给赋值,回报错
***也不可以在最后用send,最后一个yield不可以接受赋值
# 获取移动平均值 # avg = sum/count # def average(): # sum = 0 # count = 0 # avg = 0 # while True: # num = yield avg # sum += num # 10 # count += 1 # 1 # avg = sum/count # # avg_g = average() # avg_g.__next__() # avg1 = avg_g.send(10) # avg1 = avg_g.send(20) # print(avg1)
#装饰器和生成器的获取移动平均值 def wrappers(func): #func -->avg_func 该装饰器就是为了第一次使用send不用写__next__ def inner(*args,**kwargs): ret = func(*args,**kwargs) # ret是一个生成器 ret.__next__() #使用send之前必须先使用__next__() return ret return inner @wrappers #avg_func = wrappers(avg_func) def avg_func(): sum = 0 count = 0 avg = 0 while 1: num = yield avg sum += num count += 1 avg = sum / count avg_g = avg_func() #avg_g 是一个生成器 此时avg_func()是inner() 所以返回值为ret即一个生成器 print(avg_g.send(10)) #10.0 print(avg_g.send(20)) #15.0