运维八一 运维八一
首页
运维杂记
编程浅尝
周积跬步
专栏
生活
关于
收藏
  • 分类
  • 标签
  • 归档
Source (opens new window)

运维八一

运维,运维!
首页
运维杂记
编程浅尝
周积跬步
专栏
生活
关于
收藏
  • 分类
  • 标签
  • 归档
Source (opens new window)
  • Go

  • Python

    • 前言

    • python基础

      • 变量
      • 格式化输出和运算符
      • 数据类型
      • 流程控制
      • 文件处理
      • 字符编码原理
      • 函数概念
      • 函数嵌套和作用域
      • 装饰器-迭代器-生成器
        • 1. 装饰器
        • 2. 迭代器
        • 3. 生成器
      • 递归函数和匿名函数
      • 内置函数
  • Shell

  • Java

  • Vue

  • 前端

  • 编程浅尝
  • Python
  • python基础
lyndon
2023-06-07
目录

装饰器-迭代器-生成器

# 1. 装饰器

**装饰器:**装饰它人的工具,装饰器本身可以是任意可调用对象,被装饰的对象本身也可以是任意可调用对象

为什么要使用装饰器?

  • 装饰器的功能:在不修改原函数及其调用方式的情况下对原函数功能进行扩展
  • 装饰器的本质:就是一个闭包函数

装饰器的开放封闭原则:

  • 对扩展是开放的
  • 对修改是封闭的

装饰器的遵循的原则:

  • 不修改被装饰对象的源代码
  • 不修改被调用对象的调用方式
@装饰器名,必须写在被装饰对象的正上方,并且是单独一行
import time

def timmer(func):
    # func=index或者home
    def wrapper():
        start=time.time()
        func()
        stop=time.time()
        print('run time is %s' %(stop-start))
    return wrapper

@timmer # index=timmer(index)把下面被装饰函数index当做参数传递给timmer
def index():
    time.sleep(3)
    print('welcome to index')

@timmer # home=timmer(home)
def home():
    time.sleep(2)
    print('welcome to home page')

index()
home()

import time

def timmer(func):
    def wrapper(*args,**kwargs): # 能接受任意参数
        start=time.time()
        res=func(*args,**kwargs)
        stop=time.time()
        print('run time is %s' %(stop-start))
        return res
    return wrapper

@timmer # index=timmer(index)
def index():
    time.sleep(3)
    print('welcome to index')
    return 123

@timmer # home=timmer(home)
def home(name):
    time.sleep(2)
    print('welcome %s to home page' %name)

# res=index() #res=wrapper()
# print(res)

res1=home('egon') #wrapper('egon')
print(res1)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52

实现用户认证功能:

import time
from functools import wraps
current_user={'user':None}

def timmer(func):
    @wraps(func)
    def wrapper(*args,**kwargs):
        start=time.time()
        res=func(*args,**kwargs)
        stop=time.time()
        print('run time is %s' %(stop-start))
        return res
    return wrapper
def auth(auth_type='file'):
    def deco(func):
        def wrapper(*args, **kwargs):
            if auth_type == 'file':
                if current_user['user']:
                    return func(*args, **kwargs)
                name = input('name: ').strip()
                password = input('password: ').strip()

                with open('db.txt', encoding='utf-8') as f:
                    user_dic = eval(f.read())
                if name in user_dic and password == user_dic[name]:
                    res = func(*args, **kwargs)
                    current_user['user'] = name
                    return res
                else:
                    print('user or password error')
            elif auth_type == 'mysql':
                print('mysql')

            elif auth_type == 'ldap':
                print('ldap')
            else:
                print('not valid auth_type')
        return wrapper
    return deco

@timmer #index=timmer(wrapper)
@auth() # @deco #index=deco(index) #wrapper
def index():
    '''这是index函数'''
    time.sleep(3)
    print('welcome to index')
    return 123

# print(index.__doc__)
# print(help(index))

index()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52

# 2. 迭代器

迭代:是一个重复的过程,每一次重复,都是基于上一次的结果而来

#对于像字符串、列表、元组这样的有序数据类型,可以根据索引取值
l=['a','b','c','d']
count=0
while count < len(l):
    print(l[count])
    count+=1
#对于字典、集合这样的无序数据类型,无法根据索引取值,所以就要用迭代器
dic={'name':'egon','sex':'m',"age":18}
iter_dic=iter(dic)
while True:
    try:
        k=next(iter_dic)
        print(k,dic[k])
    except StopIteration:     #使用try:except可以捕捉到异常并跳过
        break
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

可迭代对象iterable:凡是对象下有_iter__方法:对象._iter,该对象就是可迭代对象

s='hello'
l=['a','b','c','d']
t=('a','b','c','d')
dic={'name':'egon','sex':'m',"age":18}
set1={1,2,3}
f=open('db.txt')
1
2
3
4
5
6

**迭代器对象:**可迭代对象执行内置的__iter__方法,得到的结果就是迭代器对象

  • 有_iter_,执行得到仍然是迭代本身
  • 有_next_
dic={'name':'egon','sex':'m',"age":18}

i=dic.__iter__()
# print(i)     #iterator迭代器

# i.__next__() #next(i)
print(next(i))
print(next(i))
print(next(i))
print(next(i)) #StopIteration  当迭代器对象里的值取完之后会抛出异常

l=['a','b','c','d']

i=l.__iter__()
print(next(i))
print(next(i))
print(next(i))
print(next(i))
print(next(i)) #StopIteration
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

迭代器对象的优点

  • 提供了一种统一的(不依赖于索引的)迭代方式
  • 迭代器本身,比起其他数据类型更省内存

迭代器对象的缺点

  • 一次性,只能往后走,不能回退,不如索引取值灵活
  • 无法预知什么时候取值结束,即无法预知长度

迭代器原理类似for循环原理

l=['a','b','c','d']
for item in l: #iter_l=l.__iter__()  # for循环的本质是先使用__iter__方法把可迭代对象变成迭代器对象,然后调用__next__逐个取出值,取值完成后不使用try:except也不会抛出异常
    print(item)
1
2
3

判断可迭代对象与迭代器对象方法:

  • 判断内部是不是实现了__next__方法
  • Iterable 判断是不是可迭代对象
  • Iterator 判断是不是迭代器
from collections import Iterable,Iterator
s='hello'
l=['a','b','c','d']
t=('a','b','c','d')
dic={'name':'egon','sex':'m',"age":18}
set1={1,2,3}
f=open('a.txt')
#isinstance、Iterable判断数据是否是可迭代对象
print(isinstance(s,Iterable))
print(isinstance(l,Iterable))
print(isinstance(t,Iterable))
print(isinstance(dic,Iterable))
print(isinstance(set1,Iterable))
print(isinstance(f,Iterable))

#isinstance、Iterator判断数据是否是迭代器对象
print(isinstance(s,Iterator))
print(isinstance(l,Iterator))
print(isinstance(t,Iterator))
print(isinstance(dic,Iterator))
print(isinstance(set1,Iterator))
print(isinstance(f,Iterator))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

判断range函数和map函数

map1=map(abs,[1,-2,3,-4])
print(isinstance(map1,Iterable))
print(isinstance(map1,Iterator))#map方法自带迭代器

s=range(100)#是一个可迭代的,但是不是迭代器
print(isinstance(s,Iterable))

print(isinstance(s,Iterator))
1
2
3
4
5
6
7
8

# 3. 生成器

生成器的定义:在函数内部包含yield关键字,那么该函数执行的结果是生成器

生成器的好处:不会一下在内存中生成太多的数据

生成器的本质就是迭代器

python中提供的生成器:生成器函数 和 生成器表达式

yield的功能:

  • 把函数的结果做成迭代器(以一种优雅的方式封装好_iter_,_next_)
  • 函数暂停与再继续运行的状态是由yield控制
def func():
    print('first')
    yield 11111111
    print('second')
    yield 2222222
    print('third')
    yield 33333333
    print('fourth')
g=func()
print(next(g)) #函数运行到第一个yield时会返回1111,并暂停函数的运行
print('======>')
print(next(g)) #再次运行函数,函数会接着往下运行,返回22222,并暂停函数
print('======>')
print(next(g))
print('======>')
print(next(g))
for i in g: #i=iter(g)
    print(i)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

应用场景1:

假如我想让工厂给学生做校服,生产2000000件衣服,我和工厂一说,工厂应该是先答应下来,然后再去生产,我可以一件一件的要,也可以根据学生一批一批的找工厂拿。而不能是一说要生产2000000件衣服,工厂就先去做生产2000000件衣服,等回来做好了,学生都毕业了。。。

def make_cloth():
    for i in range(1,20000):
        yield '第%s件衣服'%(i)
ret = make_cloth()
print(next(ret))
print(next(ret))
print(next(ret))
for i in range(100):
    print(next(ret))
1
2
3
4
5
6
7
8
9

应用场景2:

计算移动平均值

# 必须先用next再用send
def average():
     total=0 #总数
     day=0 #天数
     average=0 #平均数
     while True:
         day_num = yield average   #average=0
         total += day_num
         day += 1
        average = total/day
avg=average() #直接返回生成器
next(avg)#激活生成器,avg.send(),什么都不传的时候send和next的效果一样
print(avg.send(10))
print(avg.send(20))#send   1.传值 2.next
print(avg.send(30))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

应用场景3:

带装饰器的计算移动平均值

# 让装饰器去激活
def wrapper(func):
    def inner(*args,**kwargs):
        ret = func(*args,**kwargs)
        next(ret)
        return ret
    return inner

@wrapper
def average():
    total=0 # 总数
    day=0  # 天数
    average=0 #平均数
    while True:
        day_num = yield average   # average=0
        total += day_num
        day += 1
        average = total/day

ret=average() #直接返回生成器
print(ret.send(10))
print(ret.send(20)) # send   1.传一个值过去 2.让当前yield继续执行
print(ret.send(30))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

应用场景4:

生成器监听文件例子

import time

def tail(filename):
    f = open(filename)
    f.seek(0, 2) #从文件末尾算起
    while True:
        line = f.readline()  # 读取文件中新的文本行
        if not line:
            time.sleep(0.1)
            continue
        yield line

tail_g = tail('tmp')
for line in tail_g:
    print(line)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

yield与return的比较:

  • 相同:都有返回值的功能

  • 不同:return只能返回一次值,而yield可以返回多次值

def my_range(start,stop):
    while True:
        if start == stop:
            raise StopIteration   #raise会自动抛出异常
        yield start
        start+=1

g=my_range(1,3)
#
print(next(g))
print(next(g))
print(next(g))
1
2
3
4
5
6
7
8
9
10
11
12

yield的表达式应用

def eater(name):
    print('%s 说:我开动啦' %name)
    food_list=[]
    while True:
        food=yield food_list
        food_list.append(food) #['骨头','菜汤']
        print('%s eat %s' %(name,food))

alex_g=eater('alex')
#第一阶段:初始化
next(alex_g)           #等同于alex_g.send(None)
print('===========>')

#第二阶段:给yield传值
print(alex_g.send('骨头')) #1 先给当前暂停位置的yield传骨头 2 继续往下执行,直到再次碰到yield,然后暂停并且把yield后的返回值当做本次调用的返回值
# print('===========>')
print(alex_g.send('菜汤'))
print(alex_g.send('狗肉包子'))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

通过两个函数之间交互传参:

def eater(name):
    print('%s 说:我开动啦' %name)
    food_list=[]
    while True:
        food=yield food_list
        food_list.append(food) #['骨头','菜汤']
        print('%s eat %s' %(name,food))

def producer():
    alex_g=eater('alex')
    #第一阶段:初始化
    next(alex_g)
    #第二阶段:给yield传值
    while True:
        food=input('>>: ').strip()
        if not food:continue
        print(alex_g.send(food))

producer()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

使用装饰器完成初始化:

#解决初始化问题
def init(func):
    def wrapper(*args,**kwargs):
        g=func(*args,**kwargs)
        next(g)         #初始化相当于next(alex_g)
        return g
    return wrapper

@init
def eater(name):
    print('%s 说:我开动啦' %name)
    food_list=[]
    while True:
        food=yield food_list
        food_list.append(food) #['骨头','菜汤']
        print('%s eat %s' %(name,food))

alex_g=eater('alex')
# 第二阶段:给yield传值
print(alex_g.send('骨头')) #1 先给当前暂停位置的yield传骨头 2 继续往下执行,直到再次碰到yield,然后暂停并且把yield后的返回值当做本次调用的返回值
print('===========>')
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
上次更新: 2023/07/05, 16:57:02
函数嵌套和作用域
递归函数和匿名函数

← 函数嵌套和作用域 递归函数和匿名函数→

最近更新
01
ctr和crictl显示镜像不一致
03-13
02
alpine镜像集成常用数据库客户端
03-13
03
create-cluster
02-26
更多文章>
Theme by Vdoing | Copyright © 2015-2024 op81.com
苏ICP备18041258号-2
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式