第12天 装饰器和生成器模块

一、有参装饰器

1.有参装饰器的功能

在给函数添加功能的时候可以通过参数控制具体的操作(操作不固定)

2.怎么写有参装饰器

def 函数名0(装饰器的参数列表)
    def 函数名1(func):
        def 函数名2(*args, **kwargs):
            result = func(*arges, **kwargs)
            新功能
            return result
        return 函数名2
    return 函数名1
    
   
def 函数名(装饰器的参数列表) 
    无参装饰器
    return 无参装饰器的函数名
    

有参装饰器的用法:
@函数名0(装饰器实参列表)

写一个装饰器可以在函数结束后打印指定的任意提示信息

def add_message(msg):
    def test1(func):
        def new_func(*args, **kwargs):
            result = func(*args, **kwargs)
            print(msg)
            return result
        return new_func
    return test1


@add_message('====after====')
def func1(x, y):
    print(x+y)


func1(10, 20)

练习:写一个装饰器,在原函数返回值的基础上减去指定的值

@sub(10) @sub(30)

def sub(num):
    def test(func):
        def new_func(*args, **kwargs):
            result = func(*args, **kwargs)
            if type(result) in (int, float, complex):
                return result - num
            return result
        return new_func
    return test

二、迭代器

1.什么是迭代器(iter)

迭代器是容器型数据类型(序列)
特点:a.不能同时查看所有元素(打印看不到里面的元素)
b.不能统计个数
c.获取元素的时候只能一个一个的取(每次取最上层的那个),每次获取元素该元素就会从迭代器中消失(取一个就少一个)

2.创建迭代器

迭代器的创建有两种方式
1)通过iter将其他序列转换成迭代器
2)创建生成器

iter1 = iter([10, 20, 30, 40])
print(iter1)
# print(len(iter1))    # 报错!

iter2 = iter('hello')
print(iter2)

3.获取元素

不管通过什么样的方式获取到了迭代器中的元素,对应的元素都会从迭代器中消失

1)取单个元素
next(迭代器) - 获取迭代器最上层的一个数据(如果迭代器为空,就会报StopIteration错误)

2)遍历
for 变量 in 迭代器:
pass

print(next(iter1))   # 10
print(next(iter1))   # 20
next(iter1)
print(next(iter1))   # 40
# print(next(iter1))   # 报错!  StopIteration

for x in iter2:
    print(x)

# print(next(iter2))   # 报错!  StopIteration


iter3 = iter('python!')
list1 = list(iter3)
print(list1)
# print(next(iter3))  # 报错!  StopIteration


iter4 = iter('python123')
next(iter4)
for x in iter4:
    print('x:', x)

三、生成器

1.什么是生成器(generator)

生成器的本质就是迭代器(迭代器的特点和获取元素的方式生成器都适用)

2.怎么创建生成器

调用一个带有yield关键字的函数就可以创建一个生成器对象
(如果被调用的函数里面有yield,不会执行函数体,也不会获取函数返回值)

def func1():
    print('======')
    print('++++++')
    yield
    return 100


re = func1()
print(re)   # <generator object func1 at 0x10d9380d0>

3.怎么确定生成器中产生的数据

产生数据的个数: 看执行完生成器对应的函数的函数体会遇到几次yield()
产生的数据的值: 看每次遇到的yield后面的数据是什么,没有数据就是None

def func2():
    yield 100
    yield 'abc'
    for x in range(3):
        yield x


gen1 = func2()
print(gen1)
print(list(gen1))    # [100, 'abc', 0, 1, 2]


def func3(x):
    yield 10
    if x & 1:
        yield 20
    return 30
    yield 30


gen2 = func3(5)
print(list(gen2))  # [10, 20]

gen3 = func3(4)
print(list(gen3))   # [10]

4.生成器产生数据的原理

调用函数创建生成器对象的时候不会执行函数体,获取生成器中的元素的时候才会执行。
第一次获取元素会从函数体开始的位置开始执行,执行到第一次yield就停下来,并且将yield后面的数据作为这次获取到的元素。后面每次获取元素的时候都是从上次结束的位置接着往后执行,执行到下一次yield又会停下来。如果从当前位置开始执行到函数结束没有遇到yield,如果是next就会报StopIteration错误。

def func4():
    print('======1======')
    yield 100
    print('======2======')
    yield 200
    print('======3======')
    yield 300


gen4 = func4()
print(next(gen4))
for _ in range(5):
    print('~~~~~~~~~~')

print(next(gen4))
print(next(gen4))
# print(next(gen4))    # 报错! StopIteration

gen5 = func4()
gen6 = func4()
print(next(gen5))    # 100
print(next(gen5))    # 200
print(next(gen6))    # 100


def func5():
    for x in range(5):
        yield x*2


print(next(func5()))    # 0
print(next(func5()))    # 0

练习:写一个产生学号的生成器,能够产生指定学科001~999的学生学号

python学生: python001 ~ python999

java学生:java001 ~ java999

def create_num(subject: str):
    for x in range(1, 1000):
        yield f'{subject}{x:0>3}'
        # yield subject+str(x).zfill(3)


python_nums = create_num('python')
print(next(python_nums))
print(next(python_nums))

java_num = create_num('java')
print(next(java_num))

练习: 写一个偶数生成器,能够产生所有的正的偶数

def even_numbers():
    num = 2
    while True:
        yield num
        num += 2


even_gen = even_numbers()
for _ in range(100):
    print(next(even_gen))
print('=============')
for _ in range(50):
    print(next(even_gen))

4.生成式 - 生成器的推导式

将列表推导式的[]变成()就是生成器的推导式即生成式

result = (x**2 for x in range(10))
print(result)    # <generator object <genexpr> at 0x1018bd5d0>
print(next(result))
print(next(result))
print(next(result))
for item in result:
    print(f'item:{item}')
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值