- 迭代器
- 生成器
- 装饰器
迭代器
可迭代对象
可迭代(iter)是指支持iter的一个对象
通俗地说可以循环的对象就是可循环的对象。
可以用isinstance()判断一个对象是否为可迭代对象
可迭代对象包括:字符串,列表,字典,元组等可以循环的对象
>>> from collections import Iterable
>>> isinstance([], Iterable)
True
>>>
迭代器对象
迭代器是指iter所返回的一个支持next(I)的对象
可以被next()函数并不断返回下一个值直到抛出StopIteration异常的对象称为迭代器:Iteraor
python中的迭代对象器:生成器,map、zip、filter
for循环本质
# 首先获得Iterator对象:
it = iter([1, 2, 3, 4, 5])
# 循环:
while True:
try:
# 获得下一个值:
x = next(it)
except StopIteration:
# 遇到StopIteration就退出循环
break
生成器
Python使用生成器对延迟操作提供了支持。所谓延迟操作,是指在需要的时候才产生结果么不是立即产生结果。这也是生成器的主要好处
定义生成器的两种方法:
1、生成器函数:常规函数定义,但是,使用yield语句而不是return语句返回结果。yield语句一次返回一个结果。每个结果中间,挂起函数的状态,下次从他离开的地方继续执行。
2、生成器表达式:类似于列表推导,但是,生成器返回按需产生结果的一个对象,而不是构建一个结果列表
比如把列表生成式中的[]改成()。
>>> L = [x * x for x in range(10)]
>>> L
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> g = (x * x for x in range(10))
>>> g
<generator object <genexpr> at 0x1022ef630>
斐波那契数列
著名的斐波拉契数列(Fibonacci),除第一个和第二个数外,任意一个数都可由前两个数相加得到:
1, 1, 2, 3, 5, 8, 13, 21, 34, ...
斐波拉契数列用列表生成式写不出来,但是,用函数把它打印出来却很容易:
def fib(max):
n, a, b = 0, 0, 1
while n < max:
print(b)
a, b = b, a + b
n = n + 1
return 'done'
fib(5)
仔细观察,可以看出,fib函数实际上是定义了斐波拉契数列的推算规则,可以从第一个元素开始,推算出后续任意的元素,这种逻辑其实非常类似generator。
也就是说,上面的函数和generator仅一步之遥。要把fib函数变成generator,只需要把print(b)改为yield b就可以了:
def fib(max):
n,a,b = 0,0,1
while n < max:
#print(b)
yield b
a,b = b,a+b
n += 1
return 'done'
data = fib(10)
print(data)
print(data.__next__())
print(data.__next__())
print("干点别的事")
print(data.__next__())
print(data.__next__())
print(data.__next__())
print(data.__next__())
print(data.__next__())
注意:生成器只能遍历一次
总结:
生成器和迭代器的本质区别是什么?什么场景用生成器?什么场景下用迭代器?
生成器本质是一个迭代器。生成器不会一次性在内存中返回全部结果的列表,一次只返回一个结果。因此,生成器更加节省内存空间,比如处理一个100万个元素是列表,使用生成器并不会把内存撑爆。
举个生活的例子,吃火锅的时候,使用生成器就相当于把吃火锅的时候刷肥牛。刷一块吃一块,使用迭代器,就相当于整盘肥牛倒进锅里,在捞起来吃。
装饰器
定义:
本质是函数:(装饰其他函数)就是为了其他函数添加附加功能
原则:
1.不能修改被装饰的函数的源代码
2.不能修改被装饰的函数 的调用方式
例子:
你是一个视频网站的后端工程师,网站有以下几个模块
def home():
print("---首页----")
def america():
print("----欧美专区----")
def japan():
print("----日韩专区----")
def henan():
print("----河南专区----")
新需求:“欧美”和“河南”板块需要付费,不能改变原代码和调用方式。
user_status=False
def login(func): # 把要执行的模块从这里传进来
def inner(): # 再定义一层函数
_username = "alex" # 假装这是DB里存的用户信息
_password = "abc!23" # 假装这是DB里存的用户信息
global user_status
if user_status == False:
username = input("user:")
password = input("pasword:")
if username == _username and password == _password:
print("welcome login....")
user_status = True
else:
print("wrong username or password!")
if user_status == True:
func() # 看这里看这里,只要验证通过了,就调用相应功能
return inner # 用户调用login时,只会返回inner的内存地址,下次再调用时加上()才会执行inner函数
#america=inner
@login #america=login(america);login(america),america=inner
def america():
# login() #执行前加上验证
print("----欧美专区----")
def japan():
print("----日韩专区----")
@login
def henan():
# login() #执行前加上验证
print("----河南专区----")
def home():
print('--首页--')
home()
america()
henan()
往河南板块传个参数,结果出错了。因为....
调用henan时,其实是相当于调用的login。henan第一次调用时henan = login(henan), login就返回了inner的内存地址,第2次用户自己调用henan("3p"),实际上相当于调用的时inner,但inner定义时并没有设置参数,所以报错。
升级版:
user_status = False #用户登录了就把这个改成True
def login(auth_type): #把要执行的模块从这里传进来
def auth(func):
def inner(*args,**kwargs):#再定义一层函数
if auth_type == "qq":
_username = "alex" #假装这是DB里存的用户信息
_password = "abc!23" #假装这是DB里存的用户信息
global user_status
if user_status == False:
username = input("user:")
password = input("pasword:")
if username == _username and password == _password:
print("welcome login....")
user_status = True
else:
print("wrong username or password!")
if user_status == True:
return func(*args,**kwargs) # 看这里看这里,只要验证通过了,就调用相应功能
else:
print("only support qq ")
return inner #用户调用login时,只会返回inner的内存地址,下次再调用时加上()才会执行inner函数
return auth
def home():
print("---首页----")
@login('qq')
def america():
#login() #执行前加上验证
print("----欧美专区----")
def japan():
print("----日韩专区----")
@login('weibo')
def henan(style):
'''
:param style: 喜欢看什么类型的,就传进来
:return:
'''
#login() #执行前加上验证
print("----河南专区----")
home()
# america = login(america) #你在这里相当于把america这个函数替换了
#henan = login(henan)
# #那用户调用时依然写
america()
# henan("3p")
练习
1、用装饰器实现计算函数运行时间
import time
def cal(func):
def wraps():
start_time = time.time()
res = func()
end_time = time.time()
print("time:", end_time - start_time)
return res
return wraps
@cal
def f1():
print("in the f1")
time.sleep(1)
@cal
def f2():
print("in the f2")
time.sleep(2)
@cal
def f3():
print("in the f3")
time.sleep(3)
f1()
f2()
f3()
2、打印10以下斐波那契数列
姿势1
def fib(max):
a, b, n = 0,1,0
while b < max:
print(b)
a,b = b, a+b
n += 1
return
fib(10)
姿势2
fibs = [0,1]
for i in range(10):
fibs.append(fibs[-2]+fibs[-1])
for i in fibs:
if i <= 10:
print(i)