基础之杂货铺

╄→尐↘猪︶ㄣ 提交于 2019-12-05 06:45:58

生成器(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 '''
View Code

   注意:函数只要有了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")
yield并发效果

迭代器:(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
View Code

(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()
View Code

两个文件的程序内存是不能互相访问的,其内存地址也不一样

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()
View Code

json:用于字符串和python数据类型之间的转换,即实现不同平台之间的数据转换;pickle:支持python特有类型和所有的python数据类型转换。

pickle:只是python能识别的,java是不认识的。

建议:只dumps一次,loads一次,若要dumps几次,就dumps成好几个文件

软件目录结构规范

print(__file__)  相对路径(__file__:当前文件的文件名)

dirname 返回目录名

abspath  绝对路径

今日作业

(暂略)

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!