迭代器
- 简介:迭代器是python里面可以记住遍历位置的对象,迭代器只能往前不能往后,使用iter()创建一个迭代器,使用next()返回一个迭代器里面的元素。
- 应用场景:数列的数据规模巨大,或者数列有规律,但是通过列表推导式推导不出来
#!/usr/local/bin/python3
import sys
it = iter([1,32,43,2])
while True:
try:
print(next(it))
except StopIteration:
sys.exit()
参考:
廖雪峰的迭代器教程
菜鸟教程:迭代器与生成器
Tyson Lee的博客:详解高阶函数,闭包,装饰器
迭代器协议
迭代器协议是使用__next__()
和__iter__()
实现的
class Foo:
def __init__(self,start,stop):
self.num=start
self.stop=stop
def __iter__(self):
return self
def __next__(self):
if self.num >= self.stop:
raise StopIteration
n=self.num
self.num+=1
return n
迭代器协议实现斐波那契数列
生成器
- 简介:在python里面使用了yield的函数称为生成器,生成器返回一个迭代器,在调用生成器运行的过程中,每次遇到 yield 时函数会暂停并保存当前所有的运行信息,返回 yield 的值, 并在下一次执行 next() 方法时从当前位置继续运行。调用一个生成器函数,返回的是一个迭代器对象
应用场景:
- 列表所有数据都在内存中,如果有海量数据的话将会非常耗内存。
- 如:仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。
- 在Python中,这种一边循环一边计算的机制,称为生成器:generator
- generator保存的是算法,每次调用next(g),就计算出g的下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出StopIteration的错误。
- 简单一句话:我又想要得到庞大的数据,又想让它占用空间少,那就用生成器
例子:
最简单的创建生成器的例子
>>> g = (x * x for x in range(10))
>>> g
<generator object <genexpr> at 0x1022ef630>
#!/usr/bin/python3
import sys
def fibonacci(n): # 生成器函数 - 斐波那契
a, b, counter = 0, 1, 0
while True:
if (counter > n):
return
yield a
a, b = b, a + b
counter += 1
f = fibonacci(10) # f 是一个迭代器,由生成器返回生成
while True:
try:
print (next(f), end=" ")
except StopIteration:
sys.exit()
参考: 廖雪峰的生成器教程
装饰器
参考:
B站的视频教程
廖雪峰的装饰器教程
菜鸟教程装饰器
学装饰器前需要理解以下知识:
大家不要觉得这里啰嗦哈,认真看肯定有收获
函数也是变量
,我们那些普通的变量,比如定义x=1的时候,我们1会实实在在地存在内存里面,然后把x指向1,当在赋值x=y的时候,就把y也指向1了。当我们使用del去删除x和y的时候,那么就没有变量指向1这个内存地址了,这个1就会被Python解释器回收掉,那么如果没有被删的话,它会不会被回收呢,答案是不会,除非程序运行结束了,如果没有被删的话,它会一直贮存在内存里面,不会被回收,只要这个x变量存在,它就永远不会被删除,因为x已经用了这个内存了,就是说1是有人用了的,也就是其实他内存里面有个计数器,它每隔多长时间,就(相当于)刷新一下,看哪些没有被引用就把它清除,直到程序结束就都清空了,我们del的时候是吧x这个引用摘掉了,但那个1还在内存里面,然后Python垃圾回收发现这个1哎它没有引用,就把它删掉。- 装饰器对被装饰函数是完全透明的,也就是说,装饰器不会对要加功能的函数的源代码进行修改,而且也不会改变函数的调用方式。
- 装饰器其实就是使用了嵌套函数和高阶函数的知识,可以看本博的装饰器进阶的部分,都嵌套两层了
简介:装饰器本质上就是一个函数,它用来给别的函数增加功能。
装饰器可以在代码运行期间动态地增加函数的功能,当我们想要给多个函数增加相同的功能,一个一个地区修改这些函数效率很低,而且代码混乱,我们可以采用装饰器
看一个例子:
#!/usr/local/bin/python3
import time
def display_time(func):
def wrapper():
t1 = time.time()
func()
t2 = time.time()
print(t2-t1)
return wrapper
def is_Prime(num):
if num < 2:
return True
elif num == 2:
return False
else:
for i in (2,num):
if num % i == 0:
return False
return True
@display_time
# 这里的原理是find_Prime=display_time(find_Prime)
# 相当于偷梁换柱了,我们后面再调用的时候实际上调用的是display_time
def find_Prime():
for i in range(2,10000):
if is_Prime(i):
print(i)
find_Prime()
但是如果我们的调用装饰器的函数里面要返回一个值的话,可以这样写,修改装饰器代码的第六行和加上第九行
#!/usr/local/bin/python3
import time
def display_time(func):
def wrapper():
t1 = time.time()
result = func()
t2 = time.time()
print(t2-t1)
return result
return wrapper
def is_Prime(num):
if num < 2:
return True
elif num == 2:
return False
else:
for i in (2,num):
if num % i == 0:
return False
return True
@display_time
def find_Prime():
count = 0
for i in range(2,10000):
if is_Prime(i):
count += 1
return count
再进一步,如果我们要往装饰器里面传参数,比如我不一定是计算2到10000中的素数,我要计算2到n里面的素数,可以这样改写装饰器,在wrapper()改成wrapper(n),func()改成func(n)就行
def display_time(func):
def wrapper(n):
t1 = time.time()
result = func(n)
t2 = time.time()
print(t2-t1)
return result
return wrapper
def is_Prime(num):
if num < 2:
return True
elif num == 2:
return False
else:
for i in (2,num):
if num % i == 0:
return False
return True
@display_time
def find_Prime(n):
count = 0
for i in range(2,n):
if is_Prime(i):
count += 1
return count
find_Prime(10000)
但是以上代码写死了,就只能传一个参数,如果我们想要被装饰器的函数可以带0个或多少个参数都可以,怎么办。此时我们可以吧def wrapper(n)
改成def wrapper(*args,**kwargs)
装饰器进阶骚操作
这上面的装饰器代码都只实现了增加函数的功能,以及接受参数,以及可以返回函数的结果,但是还没有实现进阶骚操作。
需求:我想编写一个登录跳转的程序,比如通过密码,用户名进行从首页登录到其他页面,这时做运维的小伙伴知道,我们登录可以账号密码登录,又可以ldap的方式登录,那么我想让用户两种方式都登录,如果编写两个装饰器,那就low到爆,这时候我们可以给他再嵌一套。
import time
user,passwd = 'alex','abc123'
def auth(auth_type):
print("auth func:",auth_type)
def outer_wrapper(func):
def wrapper(*args, **kwargs):
print("wrapper func args:", *args, **kwargs)
if auth_type == "local":
username = input("Username:").strip()
password = input("Password:").strip()
if user == username and passwd == password:
print("\033[32;1mUser has passed authentication\033[0m")
res = func(*args, **kwargs) # from home
print("---after authenticaion ")
return res
else:
exit("\033[31;1mInvalid username or password\033[0m")
elif auth_type == "ldap":
print("搞毛线ldap,不会。。。。")
return wrapper
return outer_wrapper
def index():
print("welcome to index page")
@auth(auth_type="local")
# home = wrapper(),加了括号,已经调用了wrapper()
def home():
print("welcome to home page")
return "from home"
@auth(auth_type="ldap")
def bbs():
print("welcome to bbs page")
index()
print(home()) #wrapper()
bbs()
参考:alex运维开发的博客