什么是可迭代的 含有__iter__方法的就是可迭代的:
python 可迭代对象——Iterable
Python中经常使用for来对某个对象进行遍历,此时被遍历的这个对象就是可迭代对象,
像常见的list、tuple、dict、set、str都是。如果给一个准确的定义的话,就是只要它
定义了可以返回一个迭代器的iter方法,或者定义了可以支持下标索引的getitem方法,
那么它就是一个可迭代对象。
python 迭代器对象——Iterator
迭代器是通过next()来实现的,每调用一次他就会返回下一个元素,
当没有下一个元素的时候返回一个StopIteration异常,所以实际上定义
了这个方法的都算是迭代器。迭代器一定是可迭代对象,反过来则不一定
成立。用iter()函数可以把list、dict、str等Iterable变成Iterator
什么是迭代器 含有__iter__方法和__next__方法的就是迭代器
Iterable 判断是不是可迭代的。Iterator判断是不是迭代器
1 l = [1,2,3]
2 new_l = iter(l)
3 print(new_l.__next__())
4 from collections import Iterable,Iterator
5 print(range(1000000))
6 print(isinstance(range(10000000),Iterable))
7 print(isinstance(range(10000000),Iterator))
py2 rangge 不管range多少 会生成一个列表用来存储所有的值
py3 range 不管range多少 都不会实际的生成任何一个值
迭代器的优势:
节省内存
取一个值就能进行接下来的计算,而不需要等待所有的值都计算出来才开始接下来的运算--快
迭代器的特性:惰性运算
1 for i in range(100):
2 print(i)
3 f = open()
4 for line in f:
5 print(f)
列表 字典 元组 字符串 集合 rangge 文件句柄 enumerate 所有能for循环的都是可迭代的,都可以使用next
方法变成一个迭代器
生成器 Genareter
自己写的迭代器就是一个生成器
两种自己写生成器(迭代器)的机制:生成器函数 生成器表达式
生成器函数
1 def close(num):
2 ret = []
3 for i in range(num):
4 ret.append('cloth%s'%i)
5 return ret
6 def close_g(num):
7 for i in range(num):
8 yield 'cloth%s' %i #凡是带有yield的函数就是一个生成器函数
9 g = close_g(10000)
10 print(g.__next__())
11 print(g.__next__())
12 print(g.__next__())
13 print(g.__next__())
14
15 def func1():
16 print('1111')
17 yield 1
18 print('222222')
19 yield 2
20 yield 3 #记录当前所在的位置,等待下一次next来触发函数的状态
21 yield 4
22 g = func1()
23 print(g.__next__())
24 print(g.__next__())
25 for i in g:
26 print(i)
凡是带有yield的函数就是一个生成器函数
生成器函数的调用不会触发代码的执行,而是会返回一个生成器(迭代器)
想要生成器函数执行,需要用next
s使用生成器监听文件输入的例子
1 def listen_file():
2 with open('userinfo') as f:
3 while True:
4 line = f.readline()
5 if line.strip():
6 yield line.strip()
7 time.sleep(0.1)
8 g = listen_file()
9 for line in g:
10 print(line)
send 关键字
1 def func():
2 print(1111)
3 ret1 = yield 1
4 print(2222,ret1)
5 ret2 = yield 2
6 print(3333,ret2)
7 yield 3
8
9 g = func()
10 ret = g.__next__()
11 print(ret)
12 g1 = g.send('alex') #send 就是在执行next的过程中,生成一个参数,给生成器函数的内部
13 print(g1)
向生成器中传递值,有一个激活的过程,第一次必须用next触发,后边才可以使用send传参
例子
计算移动平均值
月度 的 天平均收入
第一天200元收入,第二天300元,第三天500元
200 250 333.3333
1 def average():
2 sum_money = 0
3 day = 0
4 avg = 0
5 while True:
6 money = yield avg
7 sum_money += money
8 day += 1
9 avg = sum_money / day
10 g = average()
11 next(g)
12 print(g.send(200))
13 print(g.send(300))
预激生成器
1 def init(func):
2 def inner(*args,**kwargs):
3 ret = func(*args,**kwargs)
4 next(ret) #
5 return ret
6 return inner
7 @init
8 def average():
9 sum_money = 0
10 day = 0
11 avg = 0
12 while True:
13 money = yield avg
14 sum_money += money
15 day += 1
16 avg = sum_money / day
17 g = average()
18 next(g) #预激活
19 print(g.send(200))
20 print(g.send(300))
21 预激活做成装饰器,可以节省很多时间 叫做预激生成器
22 yield from
23 def generator_func():
24 for i in range(5):
25 yield i
26 for j in 'hello':
27 yield j
28
29 g = generator_func()
如何从生成器中取值
第一种 使用next取值 随时可以停止,最后一次会报错
print(next(g))
第二种 使用for循环取值 从头到尾遍历一次,不遇到break不停止
for i in g:
print(i)
第三种 list取值或者tuple取值 数据类型的强转 会把所有的数据都加载到内存里,非常的浪费内存
1 print(g)
2 print(list(g))
3 def generator_func():
4 for i in range(5):
5 yield i
6 for j in 'hello':
7 yield j
8 yield from range(5)
9 yield from 'hello'
10 g1 = generator_func()
11 g2 = generator_func()
12 for i in g:
13 print(i)
14 print(g1,g2)
15 next(g1)
16 print(next(g1))
17 print(next(g1))
生成器函数 是我们python程序员实现迭代器的一种手段
主要手段,在函数中 含有yield 有yield就不建议使用return
调用一个生成器函数,不会执行这个函数中的代码,只是会获得一个生成器(迭代器)
只有从生成器中取值的时候,才会执行函数内部的代码,且每获取一个数据才执行得到这个数据的代码
获取数据的方式包括, next send 循环数据类型的强制转换
yield 返回值的简便方法,如果本身就是循环一个可迭代的,且要把可迭代数据中的每一个元素都返回,可以用yield from
使用send的时候,在生成器创造出来之后需要进行预激活,这一步可以使用装饰器完成
生成器的特点:节省内存 惰性运算
生成器用来解决内存问题和程序功能之间的解耦
列表推导式
new_list=[]
for i in range(10):
new_list.append(i**2)
print(new_list)
print([i**2 for i in range(10)])
print([abs(i) for i in [1,2,3,-5,6,20,17]])
l = [1,2,3,41,-5]
print([num for num in l if num%2 == 1])
#30以内所有能被3整除的数
print([num for num in range(30) if num%3 == 0])
#30以内所有能被3整除的数的平方
print([num**2 for num in range(30) if num%3 == 0])
#知道嵌套列表中名字含有两个‘e’的所有名字
names = [['Tom','Billy','Jefferson','Arderm','Wesley','Steven','Joe'],
['alice','Jill','Ana','Wendy','Jennifer','Sherry','Eva']]
print([name for name_list in names for name in name_list if name.count('e') == 2])
生成器表达式
#30以内所有能被3整除的数
l = [num for num in range(30) if num%3 == 0] #列表推倒式 排序的时候使用列表推导式
g = (num for num in range(30) if num%3 == 0) #生成器表达式 庞大数据量的时候使用生成器表达式
print(l)
print(g)
林海峰
egg_list = ['jidan%s' %i for i in range(10)] #列表解析多少鸡蛋
laomuji = ('jidan%s' %i for i in range(10)) #生成器表达式 用一个鸡蛋拿一个鸡蛋
print(laomuji)
print(laomuji.__next__())
print(egg_list)
面试题
#第一个
def demo():
for i in range(4):
yield i
g = demo()
g1 = (i for i in g)
g2 = (i for i in g1)
print(list(g1))
print(list(g2))
#第二个
def add(n,i):
return n+i
def test():
for i in range(4):
yield i
g=test()
for n in [1,10]:
g = (add(n,i) for i in g)
n = 1
g = (add(n, i) for i in g)
下边的g是上边g的生成器表达式 n永远都是最后的10
n = 10
g = (add(10, i) for i in (add(10, i) for i in [0,1,2,3])) #(add(10, i) for i in [0,1,2,3])=[10,11,12,13]
g = (add(10, i) for i in [10,11,12,13])
g = [20,21,22,23]
print(list(g))
#第三题 这种问题跟循环前面的数字没关系 只跟最后一个和有多少个有关系。
def add(n,i):
return n+i
def test():
for i in range(4):
yield i
g=test()
for n in [1,3,10]:
g = (add(n,i) for i in g)
n = 1
g = (add(n,i) for i in g)
n = 3
g = (add(n,i) for i in g)
n = 10
g = (add(n,i) for i in (add(n,i) for i in (add(n,i) for i in [0,1,2,3])))
#然后 n = 10 相加
g = (add(n,i) for i in (add(n,i) for i in [10,11,12,13]))
g = (add(n,i) for i in [20,21,22,23])
g = [30,31,32,33]
print(list(g))
一个生成器只能取一次值
生成器在不找他要值的时候,始终不执行
当他执行的时候,要以执行时候的所有变量值为准
迭代器
什么是可迭代的 含有__iter__方法的就是可迭代的:
python 可迭代对象——Iterable
Python中经常使用for来对某个对象进行遍历,此时被遍历的这个对象就是可迭代对象,
像常见的list、tuple、dict、set、str都是。如果给一个准确的定义的话,就是只要它
定义了可以返回一个迭代器的iter方法,或者定义了可以支持下标索引的getitem方法,
那么它就是一个可迭代对象。
python 迭代器对象——Iterator
迭代器是通过next()来实现的,每调用一次他就会返回下一个元素,
当没有下一个元素的时候返回一个StopIteration异常,所以实际上定义
了这个方法的都算是迭代器。迭代器一定是可迭代对象,反过来则不一定
成立。用iter()函数可以把list、dict、str等Iterable变成Iterator
什么是迭代器 含有__iter__方法和__next__方法的就是迭代器
Iterable 判断是不是可迭代的。Iterator判断是不是迭代器
生成器
自己写的迭代器就是一个生成器
生成器函数
凡是带有yield的函数就是一个生成器函数
生成器函数的调用不会触发代码的执行,而是会返回一个生成器(迭代器)
想要生成器函数执行,需要用next
生成器的预激活过程
预激活做成装饰器,可以节省很多时间 叫做预激生成器
列表推倒式 和 生成器表达式
l = [num for num in range(30) if num%3 == 0] #列表推倒式 排序的时候使用列表推导式
g = (num for num in range(30) if num%3 == 0) #生成器表达式 庞大数据量的时候使用生成器表达式
如何从生成器中取值
第一种 使用next取值 随时可以停止,最后一次会报错
print(next(g))
第二种 使用for循环取值 从头到尾遍历一次,不遇到break不停止
for i in g:
print(i)
第三种 list取值或者tuple取值 数据类型的强转 会把所有的数据都加载到内存里,非常的浪费内存
预激活做成装饰器,可以节省很多时间 叫做预激生成器
内置函数 不def 定义函数可以直接 加()的都是内置函数
print()
input()
len()
open()
tuple()
list()
bool()
set()
id()
str()
abs()
作用域相关 平时不用
locals() #返回本地作用域中的所有名字
globals() #返回全局作用域中的所有名字
enumerate 可以按照索引和
l = [1,23,45]
ret = enumerate(l)
for i in ret:
print(i)
global 变量 关键字 声明函数内部变量对全局生效
nonlocal 变量 关键字 声明函数内部变量对本层以及下边生效
迭代器 生成器相关
range() 是一个可迭代对象 不是迭代器
range(10)
range(1,10,2)
迭代器 .__next__()
next(迭代器)
iter() .__iter__()
其他 dir 查看一个变量拥有的所有方法 不长写在代码里
print(dir([]))
dir([])
callable() 检查一个变量是否可以被调用 后边加() 就是可以被调用的
print(callable(print))
help 帮助
import os 导入模块 __import__()
某个方法属于某个数据类型的变量,就用.调用
如果某个方法不依赖于任何数据类型,就直接调用 只有内置函数和自己定义的函数是可以直接调用的
剩下的所有内容都是属于数据类型的
open
f = open('file')
f.readline()
f.writable() #可不可以写
跟内存相关
id()
hash()
对于相同可hash的数据的hash值再一次程序的执行过程中总是不变得
print(hash(12345))
print(hash('12312332'))
print(hash('12312332'))
print(hash(('1','2')))
print(hash([])) #不可以哈希
输入输出相关
input() #输入一个值才结束
print(self, *args, sep=' ', end='\n', file=None) # 打印 每一次打印会自动换行
print('我们的祖国是花园',end = '') #指定输出的结尾
print('我们的祖国是花园')
print('我们的祖国是花园')
print('我们的祖国是花园')
print(1,2,3,4,5,sep = '|') #sep 指定输出分割符
指定一个文件 把文件写入一个文件名为f的文件里
f = open('file','w')
print('a',file=f)
f.close()
打印进度条
1 import time
2 for i in range(0,101,2): #0,2,4,6,8
3 time.sleep(0.1)
4 char_num = i//2 #打印多少个'*' 4
5 if i == 100:
6 per_str = '\r%s%% : %s\n' % (i, '*' * char_num) #\r 回到行首
7 else:
8 per_str = '\r%s%% : %s\n'%(i,'*'*char_num)
9 print(per_str,end='',flush=True) # 0.01
exec eval 都可以执行字符串的看起来是python语句的
1 exec('print(123)')
2 eval('print(123)')
3 print(1+2+3+4)
4 print(exec('1+2+3+4'))
5 print(eval('1+2+3+4'))
两个都可以执行字符串类型的代码 eval有返回值简单的计算,exec没有返回值简单的流程控制
eva 只能用在你明确知道你要执行的代码是什么
1 code = '''for i in range(10):
2 print(i*'*')
3 '''
4 exec(code)
compile() 将字符串进行编译变成字节码 然后用exec 和eval执行
复数 ---- complex
实数 ---- 有理数:整数 有限循环小数 无限循环小数 和 无理数:π
虚数 ---- 虚无缥缈的数
5 + 12j == 复合的数 == 复数 复数之间不能比较大写
和数字相关 只在数据类型转换的时候才用
float 浮点数(有限循环小数 和 无限循环小数) !== 小数:有限循环小数 和 无限循环小数 无线不循环小数
浮点数
354.123 = 3.54123*10**2 = 35.4123*10
f = 1.43287432846824235244645645646
print(f)
进制转换
bin() 二进制
oct() 八进制
hex() 十六进制
0b 二进制
0o 八进制
0x 十六进制
数学运算
print(abs(-7)) 绝对值
divmod() 接收两个参数 求商取余 div 是除法 mod 是取余
print(divmod(10,2))
print(round(3.12312,2)) #做精确值 会四舍五入
print(pow(2,3)) #pow 幂运算2的3次方
print(pow(1,23,4)) # 1的23次幂取余4
sum min max
sum 求和必须是可迭代的 必须是数字
print(sum(range(10)))
print(sum([1,3,4,5,6],10))
min(iterable, *[, default=obj, key=func]) -> value
min(arg1, arg2, *args, *[, key=func]) -> value
print(min([1,23,4,5,]))
print(min(1,23,4,-4))
print(min([111,-23,4,5],key=abs),) #可以添加参数key 以绝对值的求最小值
max(*args, key=None) #可以添加参数key 以绝对值的求最小值
##数据类型有多少:int str list tuple set dict bool。。。。。
##数据结构有多少:容器数据类型list tuple set dict str
##重要的内置函数 reverse
l = [1,23,4]
l.reverse() #翻转
print(l)
l = [1,2,34,5,6]
l2 = reversed(l) #反转之后成生一个迭代器 不改变原来的列表 保留原来的列表生成一个反序迭代器
print(list(l2))
slice
l = (1,2,3,421,321,3,2131,321)
sli = slice(1,5,2)
print(l[sli])
format 如果以后对数学相关可以使用format
print(format('test','<20'))
print(format('test','>20'))
print(format('test','^20'))
###bytes 转换成bytes类型
我拿到的是gbk编码,想转换成utf-8类型 需要先转换成Unicode类型在转换成bytes的utf-8
bytearray byte类型的数组
print(bytearray('ninhao',encoding='utf-8'))
l = '2132134214sdasasdsadsa'
memoryview 切片内存
ord() #字符串转换成数字
chr() #数字转换成字符串
ascii()
print(repr('1'),repr(1)) #可以原封不动的打印出来
name = 'egg'
print('nihao%r' %name)
dict set
frozenset #集合不可变
最重要的几个 len enumerate zip filter map sorted
all 可迭代的 如果里面有一个FALSE就是FALSE
any 可迭代的 有一个True就是True
zip #拉链 可迭代的 把两个拉到一起组成新的展示 按照最短的
l = [1,2,3]
l2 = ['a','b','c']
l3 = (1,3,4)
l4 = {'k':1,'v':2}
for i in zip(l,l2,l3,l4):
print(i)
filter() 跟生成器表达式,列表推导式类似 必须跟函数的名字一起使用 用于筛选
1 def is_odd(x):
2 return x and str(x).strip()
3 ret = filter(is_odd, ['',None,' ',1,2,3,4,7,9]) #filter 生成一个迭代器 节省内存
4 for i in ret:
5 print(i)
6 print([i for i in [1,2,3,4,7,9] if i % 2 == 1])
7 from math import sqrt
8 def m(x):
9 return sqrt(x) % 1 == 0
10 ret = filter(m,range(100))
11 print(list(ret))
12 for i in ret:
13 print(i)
map()
1 ret = map(abs,[1,-4,5,19])
2 print(ret)
3 for i in ret:
4 print(i)
filter 执行了filter之后的结果集合一定是<= 执行之前的个数
filter 只管筛选,不会改变原来的值
map 元素执行前后个数不变,值可能改变了
sorted 排序 是可迭代的 可以根据要求排序
l = [1,3,4,-5,-7]
l.sort(key=abs) #sort 在愿列表的基础上进行排序
print(l)
l1 = sorted(l,key=abs) #生成一个全新的列表 排序必须读取所有的数据才可以排序,消耗内存
print(l1)
练习
l = [' ',[1,2],'hello','wordle']
l1 = sorted(l,key=len)
print(l1)
匿名函数 lambda
1 cale = lambda n:n**n
2 print(cale(10))
3 add = lambda a,b:a+b
4 print(add(1,2))
5 dic = {'k1':1,'k2':3,'k3':1}
6 print(dic[max(dic,key=lambda k:dic[k])])
7
8 res = filter(lambda x:x>10,[5,8,11,9,15])
9 print(list(res))
带key的内置函数:max mix filter map sorted 都可以跟key参数使用 或者说都可以跟lanbda合作
1 d = lambda p:p*2
2 t = lambda p:p*3
3 x = 2
4 x = d(x) # x = 4
5 x = t(x) # x = 12
6 x = d(x)
7 print(x)
现有两元组(('a'),('b')),(('c'),('d')),请使用python中匿名函数生成列表[{'a':'c'},{'b':'d'}]
匿名函数 == 内置函数和匿名函数组合 max min map filter sorted
1 ret = zip((('a'),('b')),(('c'),('d')))
2 ('a', 'c') ('b', 'd')
3 def func(tup):
4 return {tup[0]:tup[1]}
5 res = map(lambda tup:{tup[0]:tup[1]},ret)
6 print(list(res))
3.以下代码的输出是什么?请给出答案并解释。
1 def multipliers():
2 return [lambda x:i*x for i in range(4)]
3 print([m(2) for m in multipliers()])