生成器(generator)
(1)列表生成式:使代码更简洁,适合数据量比较小,如果数据量非常大,就可以用函数作生成器(如下例:斐波那契数列)

1 a = [i*2 for i in range(10)] 2 # 得到列表a=[0, 2, 4, ... , 18] 3 # 等价于 4 a = [] 5 for i in range(10): 6 a.append(i * 2) 7 补充:a = [该参数可以是函数 for i in range(10)]
(2)生成器的定义:
1)只有在调用时才会生成相应的数据,一次性的【节省内存空间】,列表生成器只要把一个列表生成式的 [ ] 改成 ( ),用next()或.__next__()取值

1 c = (i*2 for i in range(10)) # 生成器 2 print(c) 3 # c: <generator object <genexpr> at 0x01E47F00> 4 for i in c: 5 print(i) 6 7 c = [i*2 for i in range(10)] # 生成式 8 print(c) 9 # c:[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
2)只记录当前位置 c.__next__() -->取下一个数据,但只能记住当前的数据
3)只有一个c.__next__()方法(在python 3.x中)或利用函数next(c) python 2.x 是next(),常用于循环,用的不多
(3)案例引入之斐波那契数列:除第一个和第二个数外,任意一个数都可由前两个数相加得到:1,1,2,3, 5, 8, 13, 21, 34, ……

1 #!/usr/bin/env python 2 # Author:USON 3 ''' 4 def fib(max): 5 a = 0 6 b = 1 7 n = 0 8 while n < max: 9 n = a + b #0+1=1 1+1=2 2+1=3 3+2 10 b = a 11 a = n # a=1 a=2 a=3 12 print(n) 13 fib(34) 14 ''' 15 def fib2(max): 16 a, n, b = 0, 0, 1 17 while n < max: 18 print(b) 19 # a, b = b, a+b 20 # n += 1 21 t = (b, a+b) # 元组形式 22 a, b = t[0], t[1] 23 n += 1 24 return 'Done' 25 fib2(10) 26 ''' 27 1 28 1 29 2 30 3 31 5 32 8 33 13 34 21 35 34 36 55 37 '''
注意:函数只要有了yield,就不再是简单的函数了,而是一个生成器了,只有在调用的时候才会生成相应的数据,看下面这段示例代码:
def fib2(max): a, n, b = 0, 0, 1 while n < max: yield b # print(b) a, b = b, a+b n += 1 return 'Done' f = fib2(10) # print(f) # <generator object fib2 at 0x011A7F00> print(f.__next__()) print("你慢慢等吧,我出来干我的事了,等个1秒再来找你") import time time.sleep(1) # 相当于并发,当该函数执行时间非常长,没有yield就会在这等待,现在就避免等待了 print("1s时间到") print(f.__next__()) print(f.__next__()) # 执行结果: ''' 1 你慢慢等吧,我出来干我的事了,等个1秒再来找你 1s时间到 1 2 '''
yield b 保存了函数的中断状态(下次调用直接回来),可以返回到这个位置,后面的b是返回值,上面的return是异常时打印的值
def fib2(max): a, n, b = 0, 0, 1 while n < max: yield b a, b = b, a+b n += 1 return 'Done' # 是异常情况下打印的 # f = fib2(10) # print(f.__next__()) # # print("你慢慢等吧,我出来干我的事了,等个1秒再来找你") # import time # time.sleep(1) # print("1s时间到") # # print(f.__next__()) # print(f.__next__()) #加个异常处理 g = fib2(10) # 给生成器赋值,此时并非执行函数(生成器),只是变成了生成器而已 while True: try: x = next(g) # next是内置方法,这里没有下划线,效果同.__next__(),另外,Done 属异常情况 print('g:', x) except StopIteration as e: print('Generator return value:', e.value) # e.value :return的值 break
(4)案例引入之异常处理:
断点分析结果:
(5)生成器并行处理:yield实现单线程下并发运算的效果
知识整理:send唤醒(调用)yield,并传值给yield,向下继续执行;next只调用yield但不传值

1 #!/usr/bin/env python 2 # Author:USON 3 #_*_coding:utf-8_*_ 4 __author__ = 'Alex Li' 5 6 import time 7 def consumer(name): 8 print("%s 准备吃包子啦!" %name) #陈述下面干的事情 9 while True: 10 baozi = yield #第一次调用(yield没有被调用也没有传值)中断返回(保存中断状态,下次调用直接回来),当send调用时,并传值才下一步 11 print("包子[%s]来了,被[%s]吃了!" %(baozi,name)) 12 # 此时,又循环到 baozi = yield 被中断返回 13 14 def producer(name): 15 16 c = consumer('A') #仅变成生成器,而不是调用函数 17 c2 = consumer('B') 18 19 c.__next__() #开始调用迭代器,走到baozi = yield中断 20 c2.__next__() 21 22 print("老子开始准备做包子啦!") #陈述下面干的事情 23 24 for i in range(10): 25 time.sleep(1) #仅为了效果展示 26 print("做了2个包子!") #陈述下面干的事情 27 c.send(i) 28 c2.send(i) # send唤醒(调用)yield,并传值给yield,向下继续执行,next只调用yield但不传值 29 30 producer("alex")
迭代器:(isinstance()可判断是否是可迭代对象或者迭代器)
(1)可直接作用于for循环的对象,即为可迭代对象(Iterable)- 可循环的对象:
1)数据类型有:字符串str,列表list,元组tuple,字典dict,集合set,字节类型Bytes……这类集合数据类型
2)数据结构有:生成器generator,yield的生成器函数……
补充:生成器不但可以作用于for循环,还可以被next()函数不断调用,并返回下一个值,直到抛出异常StopIteration错误,表示无法继续返回下一个值了。

1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 # Author:Uson 4 5 from collections import Iterable 6 print(isinstance([], Iterable)) #True 7 print(isinstance('Uson', Iterable)) #True 8 print(isinstance(123, Iterable)) #False 9 10 print(isinstance({'name': 'Uosn'}, Iterable)) #True 11 print(isinstance({'Uosn', 'Cohui'}, Iterable)) #True 12 13 print(isinstance(('uson'), Iterable)) #True 14 print(isinstance(b'Uson', Iterable)) #True 15 16 def func(): 17 pass 18 print(isinstance(func(), Iterable)) #False 19 20 def fib(): 21 yield 22 print(isinstance(fib(), Iterable)) #True 23 24 g = ( i for i in range(10) ) 25 print(isinstance(g, Iterable)) #True
(2)迭代器定义:可以被next()函数调用,并不断返回下一个值的对象,称为迭代器(Iterator)
注意:与可迭代对象不是一回事,怎么直到有没有next()的方法呢?dir(对象) 可查看所有方法,没有就不是迭代器。
print(dir([])) print(isinstance([], Iterator)) # False print(isinstance({}, Iterator)) # False print(isinstance(123, Iterator)) # False print(isinstance("Uson", Iterator)) # False print(isinstance((), Iterator)) # False print(isinstance(b'Uson', Iterator)) # False def func(): pass print(isinstance(func(), Iterator)) #False def fib(): yield print(isinstance(fib(), Iterator)) #True g = ( i for i in range(10) ) print(isinstance(g, Iterator)) #True
(3)如何将可迭代对象变成迭代器或者说是迭代器对象?
为什么字典、列表之类的不是一个迭代器对象呢?而要通过iter()函数转一下呢?因为python的迭代器对象是一个数据流,没有固定的开始和结束,而列表有始有终。
继续:可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()
函数实现按需计算下一个数据,所以Iterator
的计算是惰性的,只有在需要返回下一个数据时它才会计算。Iterator
甚至可以表示一个无限大的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的。
# iter()把可迭代对象变成迭代器 print(isinstance(iter([]), Iterator)) # False ->True print(isinstance(iter({}), Iterator)) # False ->True # print(isinstance(iter(123), Iterator)) # False 数字不是可迭代对象 print(isinstance(iter("Uson"), Iterator)) # False ->True print(isinstance(iter(()), Iterator)) # False ->True print(isinstance(iter(b'Uson'), Iterator)) # False ->True
(4)小结:1)生成器也是迭代器,但迭代器(虽有next方法)不一定是生成器;2)底层很多东西都是使用迭代器实现的,但我们一般不用它;3)迭代器可直接用于for循环;4)c.__next__() 等价于send(None),这样send就可以在一开始就使用;5)节省内存开销。
内置方法详解
#!/usr/bin/env python # Author:USON for fun in [lambda i=i:i*2 for i in range(10)]: print(fun()) # 0,2,4,6,8,...,18 # 绝对值 abs(x) print(abs(-1)) # 1 # all(iterable) 可迭代的对象里所有元素均为真,则返回True print(all([0,-1])) # False # any(iterable) # 可迭代的对象里有一个元素为真,则返回True print(any([0,-1])) # True #不用 # ascii(object) 把可打印的对象变成字符串形式 print(ascii([0,-1])) # [0, -1] # bin(x) (数字)非字符串转二进制 print(bin(4)) # 0b100 # bool([x]) 布尔判断真假 print(bool([1, 2])) # True #不用 # bytearray([source[, encoding[, errors]]]) 把二进制变成列表形式,可以修改 a = bytes("abcde", encoding='utf-8') print(a) # b'abcde' # 字符串,二进制不可修改 b = bytearray("abcde", encoding='utf-8') print(b[0]) # a -> 97(ASCII格式) b[1] = 100 print(b) # bytearray(b'adcde') # callable() 是否可被调用(加()的就可被调用),类,函数可被调用 print(callable([])) # False # chr(数字) ASCII对应表,把对应的数字转成字符 还可以:print("%c"%48)==>0(48对应的Ascii码是0) print(chr(87)) # W # ord(字符) 相反 print(ord('W')) # 87 # classmethod(function) 类方法,后面再学 # 不用 # compile() # 底层把代码编译的过程 #(1) code = "for i in range(10): print(i)" # compile(code, '', 'exec') for循环 c = compile(code, '', 'exec') exec(c) # 0,1,2,3,4,5,6,7,8,9 #(2) code = "1+3/2*6" d = compile(code, '文件名', 'eval') # 用于编译出错时,写到这个文件去 print(eval(d)) # 10.0 # eval()实现list,dict,tuple与str之间的转化, 有for循环等语句的,用不了 # 1)eval() 函数用来执行一个字符串表达式,并返回表达式的值。 # 2)eval()函数很强大,可以直接将你所运行的代码进行python执行: # 比如说print(eval("1+2"))可以得到结果3; # 也可以:如果你的字符串直接是字典的形式,转成字典(输入端的字符串转成字典); # 还可以:进行变量的传递eval("{'age':age}",{"age":1822}) print(eval( '3 * 7' )) # 21 print(eval('pow(2,2)')) # 4 print(eval("{'name':'linux','age':27}")) # {'name': 'linux', 'age': 27} print(eval("{'name':'linux','age':age}",{"age":1822})) # {'name': 'linux', 'age': 1822} # 不用 # complex() 复数 # 讲完面向对象再学 # delattr(object, name) # dict 字典 # dir() 看方法,除了__next__,其他两个__不用管,内置,我们不用 # divmod() # 相除得到商和余数 # enumerate # for循环用于打印索引和值 # filter(function, iterable) 过滤出想要的数据(过滤大于5的数字) # (1)lambda与filter结合 res = filter(lambda n: n > 5, range(10)) # range,迭代器,lambda通常结合filter用,不单独用 for i in res: print(i) # 6,7,8,9 # 匿名函数的使用,匿名函数,用完就释放:匿名函数处理不了for循环等复杂操作,只能处理简单的三元运算等 # 三元运算 cal = lambda n: 3 if n < 4 else n print(cal(2)) # 3 def sayhi(n): print(n) sayhi(5) # 变匿名函数 (lambda n: print(n))(5) # 5 # 或 num = lambda n: print(n) num(5) # 5 cla = lambda n: n > 5 print(cla(5)) # False cla2 = lambda n: n*3 print(cla2(5)) # 15 #(2)lambda与map结合,堆传入的每一个值进行处理,变成列表 # map(f, list) f依次作用在list的每个元素 # map()函数不改变原有的list,而返回一个新的list # 用法参考:CMDB示例(New)\AutoCmdb\web\service\asset.py for fun in [lambda x, i=i:i*2 for i in range(10)]: print(fun(2)) res2 = map(lambda n: n*n, range(10)) # lambda与reduce结合 import functools res3 = functools.reduce(lambda x,y: x+y, range(10)) print("res3>>", res3) # 45 res4 = functools.reduce(lambda x,y: x*y, range(1, 10)) print("res3>>", res4) # 362880 乘阶 # frozenset([iterable)]) 冻结,不可变集合 a = frozenset([1,2,3,4]) # a.方法不可操作 # getattr() # 面向对象学 # globals() 返回的是,该文件所有的全局变量的key-value格式(字典,变量是key,值是value) # 判断变量是否存在,可以用变量是否等于key # 哈希对半查找(映射):hash(1)/hash('uson') # hash(object) # 数字转16进制 print(hex(2)) # 0x2 # 返回内存地址 id(object) # issubclass 面向对象学 # locals() 局部变量,与globals相反 print(locals()) # 'd': <code object <module> at 0x01B96D40, file "文件名", line 1>,... print(globals().get('d')) # 获取key # <code object <module> at 0x01B96D40, file "文件名", line 1> # max() # 返回(列表)最大值 # min() # 返回(列表)最大值 # oct(x) # 转八进制 print(oct(8)) # 0o10 # pow(x, y[, z]) 返回幂 print(pow(3,3)) # 27 repr(object) # 变成字符串-->'' 用于格式化输出 # reversed(seq) # 反转 # round(number[, ndigits]) # 保存n位小数 print(round(1.342, 2)) # 1.34 # set 集合 # slice() # 切片 print(range(20)[slice(2, 5)]) # range(2, 5) print([1,2,3,4,5,6,7,8][slice(2, 5)]) # [3, 4, 5] # sorted() # 排序 a = {6:1, 1:0, 9:-2} print(sorted(a.items())) # 按key排序, [(1, 0), (6, 1), (9, -2)] b = [(-4,5), (-8,6), (0,3), (8,8)] print(sorted(b)) # [(-8, 6), (-4, 5), (0, 3), (8, 8)] print(sorted(a.items(), key=lambda x:x[1])) # x:每个元素,x[1]:元素中的value # [(9, -2), (1, 0), (6, 1)] # 求和 # sum(iterable[, start]) print(sum([1,2,3], 4)) # 10 # 面向对象学 # super() # vars([object]) # 用不到 # 中文("拉链") python3.x返回迭代器,需做一次循环打印,python 2.x 中返回列表 # zip() c = [1,2,3,4] d = ['a', 'b', 'c', 'd'] for i in zip(c, d): print(i) ''' (1, 'a') (2, 'b') (3, 'c') (4, 'd') ''' # 如果a, b数量不一致,按最小的来,map()与之相反,python 3.x不可用这样用了 c = [1, 2, 3, 4] d = ['a', 'b', 'c', 'd','e'] for i in map(lambda *row:list(row), c, d): # 多个位置参数:1,'a' -> [1, ’a'] print(i) ''' [1, 'a'] [2, 'b'] [3, 'c'] [4, 'd'] ''' # __import__('decorator') # 以后再用
参考:https://docs.python.org/3/library/functions.html?highlight=built#ascii
isinstance() 函数:判断一个对象是否是一个已知的类型,类似 type()。https://www.runoob.com/python/python-func-isinstance.html
Json与Pickle数据序列化
json支持所有语言的交互,但仅支持简单的数据序列化(如:函数不支持) XML正在被json取代
json数据序列化:把字典通过字符串存进文件:(不需要字符串通过eval的转化): import json f.write(json.dumps(字典)) = json.dump(字典, f) 【写】->字符串
json数据反序列化:把字符串转化成字典取出来: import json json.loads(字符串/f.read()) = json.load(f) 【读】->字典,取key
eval不是通用的办法或者标准的方法(要求字符串是字典格式)

1 import json 2 info = { 3 'name':"Uson", 4 'age':27 5 } 6 f = open("data.text", 'w') 7 # f.write(str(info)) 8 f.write(json.dumps(info)) 9 f.close() 10 11 import json 12 f = open("data.text", 'r') 13 # data = eval( f.read()) 14 data = json.loads( f.read()) 15 print(data['age']) 16 f.close()
两个文件的程序内存是不能互相访问的,其内存地址也不一样
pickle数据序列化:把字典通过二进制存进文件(wb):
pickle数据反序列化:把二进制转化成字典取出来(rb):

1 #!/usr/bin/env python 2 # Author:USON 3 import pickle #pickle 以二进制方式存 4 5 def sayhi(name): 6 print("Hello ", name) 7 8 info = { 9 'name':"Uson", 10 'age':27, 11 'func':sayhi # sayhi() 调用内容,sayhi 调用其内存地址 12 } 13 f = open("data2.text", 'wb') 14 # f.write(pickle.dumps(info)) # 其中的函数处理方式,dumps的是函数参数-name之类的,跟print的内容无关 15 pickle.dump(info, f) # 其中的函数处理方式,dumps的是函数参数-name之类的,跟print的内容无关 16 f.close() 17 18 #!/usr/bin/env python 19 # Author:USON 20 import pickle #pickle 以二进制方式存 21 22 def sayhi(name): 23 print("Hello2--->", name) 24 25 f = open("data2.text", 'rb') 26 # data = pickle.loads(f.read()) 27 data = pickle.load(f) 28 print(data) 29 #print(data['func']("Uson")) 30 print(data['age']) 31 f.close()
json:用于字符串和python数据类型之间的转换,即实现不同平台之间的数据转换;pickle:支持python特有类型和所有的python数据类型转换。
pickle:只是python能识别的,java是不认识的。
建议:只dumps一次,loads一次,若要dumps几次,就dumps成好几个文件
软件目录结构规范
print(__file__) 相对路径(__file__:当前文件的文件名)
dirname 返回目录名
abspath 绝对路径
今日作业
(暂略)