0516Python基础-迭代器-生成器
1、昨日内容回顾
func.__name__
func.__doc__
带参数的装饰器
def wrapper_out(*args, **kwargs):
def wrapper(f):
def inner(*args, **kwargs):
"""执行被装饰函数之前的操作"""
ret = f(*args, **kwargs)
"""执行被装饰函数之后的操作"""
return ret
return inner
return wrapper
@wrapper_out('淘宝')
def func1():
pass
def wrapper1(func): func = f 函数名
def inner1():
print('wrapper1 ,before func') # 2
func()
print('wrapper1 ,after func') # 4
return inner1
def wrapper2(func): func = inner1
def inner2():
print('wrapper2 ,before func') # 1
func()
print('wrapper2 ,after func') # 5
return inner2
@wrapper2 # f = wrapper2(f) 里面的f是inner1 外面的f = inner2
@wrapper1 # f = wrapper1(f) 里面的f是函数名 外面的f = inner1
def f():
print('in f') # 3
f() # inner2()
2、迭代器
可迭代对象:内部含有__iter__
迭代器:可迭代对象.__iter__()
迭代器:内部含有__iter__且__next__
判断 __iter__ 在不在dir(对象中)
isinstance()
节省内存。
惰性机制。
单向不可逆。
for循环的机制:
while
pass
可迭代对象
迭代器
两者区别
模拟for循环机制
迭代器
可迭代对象
s1 = '123'
for i in s1:
print(i)
int object is not iterable
for i in 123:
print(i)
内部含有__iter__方法的就是可迭代对象,遵循可迭代协议。
dir
print(dir('123')) # '__iter__'
print('__iter__' in dir([1, 2, 3]))
print('__iter__' in dir({'name':'alex'}))
print('__iter__' in dir({'name'}))
print('__iter__' in dir((1, 2, 3)))
print('__iter__' in dir(1)) # False
print('__iter__' in dir(True)) # False
迭代器?可迭代对象通过.__iter__()可以转换成迭代器,满足迭代器协议。
内部含有__iter__ 且 __next__方法的就是迭代器。
l = [1, 2, 3]
l_obj = l.__iter__()
print(l_obj)
迭代器的取值两种方法:
方法一:__next__()
print(l_obj.__next__())
print(l_obj.__next__())
print(l_obj.__next__())
print(l_obj.__next__())
方法二 for循环
for i in l_obj:
print(i)
print('__next__' in dir(l_obj))
第二种判断方式:
from collections import Iterable
from collections import Iterator
print(isinstance('123', Iterable))
print(isinstance('123', Iterator))
实际上可迭代对象是不可以一个一个的一次取值的,因为他没有__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
迭代器:
1,节省内存。
2,满足惰性机制。
3,取值过程不可逆(一条路走到黑)。
3、生成器
本质上是迭代器,用python代码构建的。
生成器定义
生成器的写法
yield
send
生成器本质也是迭代器,生成器是自己用Python写的迭代器。
1,通过生成器函数构建。
2,通过生成器推导式构建。
def func1():
print(666)
return 222
ret = func1()
print(ret)
def func1():
print(11)
print(333)
yield 222
print(666)
yield 777
g_obj = func1() # 生成器对象 generator object
print(g_obj.__next__())
print(g_obj.__next__())
def cloth1():
for i in range(1,10001):
print('衣服%s' % i)
# cloth1()
def cloth2():
for i in range(1,10001):
yield '衣服%s' % i
g = cloth2()
for i in range(1,51):
print(g.__next__())
for i in range(1, 151):
print(g.__next__())
next 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'))
1,send 具有next功能。
2,send 可以给上一个yield传值。
3, 第一个取值不能使用send.
4,最后一个yield不会得到send的值。、
4、作业讲解及知识点补充。
1,装饰器:装饰器的本质是闭包。
开放封闭原则。
'''
1.对扩展是开放的
为什么要对扩展开放呢?
我们说,任何一个程序,不可能在设计之初就已经想好了所有的功能并且未来不做任何更新和修改。所以我们必须允许代码扩展、添加新功能。
2.对修改是封闭的
为什么要对修改封闭呢?
就像我们刚刚提到的,因为我们写的一个函数,很有可能已经交付给其他人使用了,如果这个时候我们对其进行了修改,
很有可能影响其他已经在使用该函数的用户。
装饰器完美的遵循了这个开放封闭原则。
'''
count = 1
def func1():
print(count)
func1()
局部作用域可以对全局作用域的变量进行引用。
count = 1
函数内部如果有变量名与全局变量名相同且对此变量进行改变,
Python 就会将你引用的那个变量视为局部定义的变量,但是局部没定义,
则他会报错。
def func1():
count1 = count + 1
print(count)
func1()
def func1():
count = 3
def inner():
count = count + 1
inner()
print(count)
func1()
函数中如果使用global + 变量 必须是第一次使用这个变量。
flag = True
def func1():
if flag:
print(333)
global flag
flag = False
func1()
flag = True
while flag:
print(333)
flag = False
print(222)
for if while 没有开辟临时空间。
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())
"""
给每个函数写一个记录日志的功能,
功能要求:每一次调用函数之前,要将函数名称,时间节点记录到log的日志中。
所需模块:
import time
struct_time = time.localtime()
print(time.strftime("%Y-%m-%d %H:%M:%S",struct_time))
"""
import time
def wrapper(f):
def inner(*args, **kwargs):
with open('log', 'a', encoding='utf-8',) as f1:
struct_time = time.localtime()
time_now = time.strftime("%Y-%m-%d %H:%M:%S", struct_time)
f1.write('在%s,执行了%s\n' % (time_now, f.__name__))
ret = f(*args, **kwargs)
return ret
return inner
@wrapper
def func1():
time.sleep(2)
print(666)
@wrapper
def func2():
time.sleep(0.1)
print(666)
@wrapper
def func3():
time.sleep(0.3)
print(666)
func1()
func3()
func2()
5、列表推导式、生成器表达式
列表推导式:能用列表推导式完成的,用python代码都可以完成。
用一句话构建一个你想要的列表。
优点:简单,稍微难理解。
缺点: 不能用debug。
li = []
for i in range(1, 12):
li.append(i)
print(li)
li = [i for i in range(1, 12)]
[ 变量(加工后的变量) for 变量 in 可迭代对象 ] 遍历模式
print(li)
li = []
for i in range(1, 12):
li.append('python%s期' % i)
print(li)
li = ['alex', 'wusir', 'taibai', 'nvshen', 'ritian']
li = ['python%s期' % i for i in range(1, 12)]
print(li)
l2 = [i+'_NB' for i in li]
print(l2)
[ 变量(加工后的变量) for 变量 in 可迭代对象 ] 遍历模式
[ 变量(加工后的变量) for 变量 in 可迭代对象 if 判断] 筛选模式
l1 = [i for i in range(1, 101) if i % 2 == 0]
print(l1)
1,筛选,100以内所有的奇数。
l2 = [i for i in range(1, 101) if i % 2 == 1]
l2 = [i for i in range(1, 101, 2)]
print(l2)
2,10以内所有数的平方。 [1,4,9,16.。。100]
print([i*i for i in range(1, 11)])
3,将100以内所有内被三整除的数留到列表中。
print([i for i in range(1,101) if i % 3 == 0])
g = (i*i for i in range(1, 11))
# print(g.__next__())
# print(g.__next__())
for i in g:
print(i)
列表推导式 简单明了,但是占内存
生成器表达式 节省内存,不易看出。
30以内所有能被3整除的数的平方
print([i*i for i in range(1, 31) if i % 3 ==0])
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)
mcase = {'a': 10, 'b': 34}
mcase_frequency = {mcase[k]: k for k in mcase}
print(mcase_frequency)