今日内容大纲
1.迭代器
2.生成器
3.知识点补充
4.列表推导式、生成器推导式
1.迭代器
1.1 可迭代对象及判断
1)对象内部有__iter__方法,就是可迭代对象。
2)判断方法
print("__iter__" in dir(int)) # False
print("__iter__" in dir(bool)) # False
print("__iter__" in dir(str)) # True
print("__iter__" in dir(list)) # True
print("__iter__" in dir(tuple)) # True
print("__iter__" in dir(dict)) # True
print("__iter__" in dir(set)) # True
with open("文件句柄测试",encoding="utf-8",mode="a") as f1:
f1.write("测试")
print("__iter__" in dir(f1))
结论:可迭代对象:str/list/tuple/dict/set/文件句柄
不可迭代对象:int/bool
1.2 可迭代对象转为迭代器
对可迭代对象使用方法:.__iter__() 即可转为迭代器
li = [11, 22, 33]
li_obj = li.__iter__()
print(li_obj)
1.3 迭代器及判断
1)迭代器:iterator
内部含有__iter__ 且 __next__方法的就是迭代器
2)判断方法
方法一:
from collections import Iterable
from collections import Iterator
li = [11, 22, 33]
li_obj = li.__iter__()
print(li_obj)
print(isinstance(li, Iterable))
print(isinstance(li_obj, Iterator))
方法二:
print("__next__" in dir(li_obj))
3)迭代器取值
方法一:通过方法:__next__()
li = [11, 22, 33]
li_obj = li.__iter__()
print(li_obj.__next__())
print(li_obj.__next__())
print(li_obj.__next__())
方法二:通过for循环
li = [11, 22, 33]
li_obj = li.__iter__()
for i in li_obj:
print(i)
4)迭代器特性:
1)迭代器节省内存;
2)迭代器满足惰性机制;
3)迭代器取值单向不可逆。
1.4 for循环的本质
实际上可迭代对象是不可以一个一个的依次取值的,因为他没有__next__方法。
for循环提供一个机制:
1)将可迭代对象转化成迭代器。
2)利用__next__进行取值。
3)用try异常处理方法防止报错。
l = [1, 2, 3, 4, 5]
l_obj = l.__iter__()
while True:
try:
print(l_obj.__next__())
except Exception:
break
2.生成器
生成器本质也是迭代器,生成器是自己用Python写的迭代器。
1)通过生成器函数构建。
2)通过生成器推导式构建。
例1:
常规函数运行
def func():
print(222)
return 666
ret = func()
print(ret)
通过生成器构建的函数
def func():
print(222)
yield 666
print(444)
yield 888
g_obj = func() # 生成器对象 generator object
print(g_obj.__next__())
print(g_obj.__next__())
执行结果:
222
666
444
888
例2:情景:客户分别向两家服装厂发出定制10000件衣服的需求,A厂选择一次性生成一万件,B厂选择先生成50件样品,后面再与客户洽谈
def func_A():
for i in range(1,10001):
print("衣服{}".format(i))
func_A()
def func_B():
for i in range(1,10000):
yield "衣服{}".format(i)
g_obj = func_B()
for v in range(1,51):
print(g_obj.__next__())
3)send
1) send 具有next功能。
2) send 可以给上一个yield传值。
3) 第一个取值不能使用send.
4) 最后一个yield不会得到send的值。
例:
def func1():
count = yield 222
print(count)
yield 777
yield 888
g_obj = func1() # 生成器对象 generator object
print(g_obj.__next__())
print(g_obj.send('wusir'))
3.知识点补充
(1)装饰器的开放封闭原则:
1)对扩展是开放的
为什么要对扩展开放呢?
我们说,任何一个程序,不可能在设计之初就已经想好了所有的功能并且未来不做任何更新和修改。所以我们必须允许代码
扩展、添加新功能。
2)对修改是封闭的
为什么要对修改封闭呢?
就像我们刚刚提到的,因为我们写的一个函数,很有可能已经交付给其他人使用了,如果这个时候我们对其进行了修改,很
有可能影响其他已经在使用该函数的用户。
装饰器完美的遵循了这个开放封闭原则。
(2)
1)局部作用域可以对全局作用域的变量进行引用。
count = 1
def func1():
print(count)
func1()
2)函数内部如果有变量名与全局变量名相同且对此变量进行改变,Python 就会将你引用的那个变量视为局部定义的变量,但是局部没定
义,则他会报错。
count = 1
def func1():
count = count + 1
print(count)
func1()
#报错
def func1():
count = 3
def inner():
count = count + 1
inner()
print(count)
func1()
#报错
3)函数中如果使用global + 变量 必须是第一次使用这个变量。for if while 没有开辟临时空间。
flag = True
def func1():
if flag:
print(333)
global flag
flag = False
func1()
flag = True
while flag:
print(333)
flag = False
print(222)
4)globals() locals()
locals :函数会以字典的类型返回 当前位置 的全部 局部变量。
globals:函数以字典的类型返回全部全局变量。
def extendList(val,list=[]):
list.append(val)
print(globals())
print(locals()) # {'list': [1], 'val': 1}
def inner():
a = 3
b = 4
print(locals())
inner()
return list
ret = extendList(1)
print(globals()) # 'ret': [1]
print(locals())
4.列表推导式,生成器推导式
(1)列表推导式:能用列表推导式完成的,用python代码都可以完成。
用一句话构建一个你想要的列表。
优点:简单,稍微难理解。
缺点: 不能用debug。
例:将1到11添加到一个列表中
常规做法
li = []
for i in range(1, 12):
li.append(i)
print(li)
列表推导式
[ 变量(加工后的变量) for 变量 in 可迭代对象 ] 遍历模式
li = [i for i in range(1, 12)]
print(li)
例2:在列表中添加python1期到python11期
li = []
for i in range(1, 12):
li.append('python%s期' % i)
print(li)
li = ['python%s期' % i for i in range(1, 12)]
print(li)
例3:在列表中每个元素后添加_NB
li = ['alex', 'wusir', 'taibai', 'nvshen', 'ritian']
l2 = [i+'_NB' for i in li]
print(l2)
(2)[ 变量(加工后的变量) for 变量 in 可迭代对象 ] 遍历模式
[ 变量(加工后的变量) for 变量 in 可迭代对象 if 判断] 筛选模式
例1:筛选1到100内的偶数
l1 = [i for i in range(1, 101) if i % 2 == 0]
print(l1)
例2:筛选1到100以内所有的奇数
l2 = [i for i in range(1, 101) if i % 2 == 1]
print(l2)
l2 = [i for i in range(1, 101, 2)]
print(l2)
例3:1到10以内所有数的平方。 [1,4,9,16.。。100]
print([i*i for i in range(1, 11)])
例4:将100以内所有内被三整除的数留到列表中。
print([i for i in range(1,101) if i % 3 == 0])
例5:30以内所有能被3整除的数的平方:
print([i*i for i in range(1, 31) if i % 3 ==0])
例6:将名字中有两个"e"的筛选出来
names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'],
['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']]
l3 = [ name for i in names for name in i if name.count('e') == 2]
print(l3)
(3)列表推导式 简单明了,但是占内存
生成器表达式 节省内存,不易看出。
g = (i*i for i in range(1, 11))
最后打印生成器
方法一:
print(g.__next__())
print(g.__next__())
print(g.__next__())
print(g.__next__())
print(g.__next__())
方法二:
for i in g:
print(i)
(4)字典推导式:将字典的key和value互换
mcase = {'a': 10, 'b': 34}
mcase_frequency = {mcase[k]: k for k in mcase}
print(mcase_frequency)