python——生成器(协程)gevent多任务, 生成器,迭代器,装饰器
#使用生成器完成斐波那锲 def create_num(all_num): a, b = 0, 1 current_num = 0 while current_num < all_num: yield a#有yield就是生成器 a, b = b, a+b current_num += 1 obj = create_num(10) for i in obj: print(i)
#使用生成器完成斐波那锲 def create_num(all_num): a, b = 0, 1 current_num = 0 while current_num < all_num: yield a#有yield就是生成器 #遇到yield会暂停,再次调用函数的时候回从yield的地方开始执行 a, b = b, a+b current_num += 1 obj = create_num(10) #生成器是一种特殊的迭代器 ret = next(obj) print(ret) ret = next(obj) print(ret) for i in obj: print(i)
使用生成器实现多任务
#使用yield完成多任务 import time def task_1(): while True: print("----1----") time.sleep(0.1) yield def task_2(): while True: print("----2----") time.sleep(0.1) yield def main(): #创建生成器对象 t1 = task_1() t2 = task_2() while True: next(t1) next(t2)#实现了函数的交替执行,交替的实现函数的多任务 if __name__=="__main__": main()
用gevent代替next
import gevent import time def f1(n): for i in range(n): print(gevent.getcurrent(),i) # time.sleep(0.1) gevent.sleep(0.1)#gevent遇到延时就会多任务,延时操作不能用上面的那种方式,必须要用这样的 def f2(n): for i in range(n): print(gevent.getcurrent(),i) # time.sleep(0.2) gevent.sleep(0.1) print("-----1-----") g1 = gevent.spawn(f1,5) print("-----2-----") g2 = gevent.spawn(f2,5) g1.join() g2.join()
import gevent import time
from gevent import monkey monkey.patch_all()#加上这个语句的话就不需要再使用gevent.sleep(0.1)这样的延时语句了,time.sleep(0.1)也可以用了 def f1(n): for i in range(n): print(gevent.getcurrent(),i) time.sleep(0.1) def f2(n): for i in range(n): print(gevent.getcurrent(),i) time.sleep(0.1) print("-----1-----") g1 = gevent.spawn(f1,5) print("-----2-----") g2 = gevent.spawn(f2,5) g1.join() g2.join()
import gevent import time from gevent import monkey monkey.patch_all()#加上这个语句的话就不需要再使用gevent.sleep(0.1)这样的延时语句了,time.sleep(0.1)也可以用了 def f1(n): for i in range(n): print(gevent.getcurrent(),i) time.sleep(0.1) def f2(n): for i in range(n): print(gevent.getcurrent(),i) time.sleep(0.1) gevent.joinall([gevent.spawn(f1,5),gevent.spawn(f2,5)])
#创建生成器 #fisrt step : 定义一个包含yield语句的函数 def test(val,step): print("----------------") cur = 0 for i in range(val): cur += i*step yield cur #函数被调用的时候并没有执行 t = test(10,2) print("=============") print(next(t))#当程序第一次调用next时,test函数才开始执行 print(next(t)) print(next(t)) print(next(t)) #程序可以使用for循环来调用next print("======================") for ele in t: print(ele)
============= ---------------- 0 2 6 12 ====================== 20 30 42 56 72 90 请按任意键继续. . .
实现迭代器
#字典列表元组都是可以迭代的,这些对象都是可迭代的,因此都是属于迭代器 #如果开发者需要实现迭代器,只要实现__iter__,__next___ class Cal: """" 一个迭代器,返回 2,4,6,8,10 """ def __init__(self): self.ini = 0 def __next__(self): #next用于返回迭代器的下一个元素 if self.ini == 10: raise StopIteration else: self.ini += 2 return self.ini def __iter__(self):#该方法返回一个迭代器(iterator) return self c = Cal() for cc in c: print(cc)
2
4
6
8
10
请按任意键继续. . .
class Cal: def __init__(self, ini,step): self.ini = ini self.step = step def __next__(self): self.ini = self.ini + self.step return self.ini def __iter__(self): return self c = Cal(10,3) for i in c: print(i) if i>20: break print("itertools " *3) import itertools as it for e in it.count(10,3): print(e) if e>20: break
13 16 19 22 itertools itertools itertools 10 13 16 19 22 请按任意键继续. . .
被装饰的函数,总是被替换成@符号所引用的函数的返回值。这是本质
因此,被装饰的函数会变成什么,完全取决于@符号所引用的函数的返回值
如果@符号所引用的函数,返回值是字符串,那被装饰的函数就被替换成了字符串
如果@符号所引用的函数,返回值是函数,那被修饰的函数在替换之后还是函数
1.
def funA(fn):
print('A')
fn()
return "fkit"
@funA
def funB():
print("B")
print(funB)
A
B
fkit
#funA()执行完成后返回的是fkit,因此funB就不再是函数,而是被替换成了字符串
2.@符号所引用的函数的返回值是还是函数
下面的程序定义 了一个装饰器函数foo, 该函数执行完成后并不是返回普通值,而是返回bar函数(这是关键),这意味着被该@foo修饰的函数最终都会被替换成bar函数
def foo(fn):
def bar(*args):
print("===1===", args)
n = args[0]
print("===2===", n * (n-1))
print(fn.__name__)
fn(n*(n-1))
print("*"*15)
return fn(n*(n-1))
return bar
@foo
def my_test(a):
print("==my_test function", a)
print(my_test)
my_test(10)
print("=="*15)
my_test(6,5)
<function foo.<locals>.bar at 0x00000217E0C6B1F0>
===1=== (10,)
===2=== 90
my_test
==my_test function 90
***************
==my_test function 90
==============================
===1=== (6, 5)
===2=== 30
my_test
==my_test function 30
***************
==my_test function 30
请按任意键继续. . .
例子:对函数进行参数检查
def auth(fn):
def auth_fn(*args):
print("------模拟权限检查------")
fn(*args)
return auth_fn
@auth
def test(a,b):
print("run test function , the args is %s, %s" %(a,b))
test(10,15)
------模拟权限检查------
run test function , the args is 10, 15
请按任意键继续. . .
python装饰器的作用就是把一个函数作为参数传给另外一个参数
import time
def step1():
for i in range(0,50):
print("Step 1........")
def step2():
for i in range(0,50):
print("Step 2........")
def step3():
for i in range(0,50):
print("step 3 ........")
def timer(func):#函数作为参数传进来
#统计函数运行时间的装饰器
def wrapper():
start = time.time()
func()
end = time.time()
used = end -start
print(f'{func.__name__} used {used}')
return wrapper
timer(step1)()#将step作为一个参数传给timer,然后使用()调用函数,这个写法不好
timer(step2)()
timer(step3)()
但是这个写法不好,可以使用@作为语法糖
import time
def timer(func):#函数作为参数传进来
#统计函数运行时间的装饰器
def wrapper():
print("程序开始运行")
start = time.time()
func()
end = time.time()
used = end -start
print("程序运行结束")
print(f'{func.__name__} 耗时 {used}')
return wrapper
@timer
#使用@符号作为语法糖,当调用step1()函数的时候,python会找到@timer,将其作为step1()函数的代理
#python会先找timer函数,将其作为step1函数的代理
def step1():
for i in range(0,50):
print("Step 1........")
@timer
def step2():
for i in range(0,50):
print("Step 2........")
@timer
def step3():
for i in range(0,50):
print("step 3 ........")
step1()
step2()
step3()