生成器&迭代器&装饰器

一、生成器【重点掌握】

# 1.概念
"""
问题:
    列表:一次性将所有的元素全部定义出来,如果在还需要访问其中的几个元素,则大量的内存空间会被浪费
        如:生成一个列表,其中有10万个元素,但是仅仅需要访问前五个元素
解决方案:
    如果需要使用前n个元素,则只有前n个元素会占用内存空间,
    在Python中,将这种一边使用,一边计算的机制被称为生成器【generator】

生成器的定义方式:
    a.将列表推导式中的[]----》()
    b.函数结合yield,定义函数生成器
"""

# 1.定义方式一
# 列表推导式
list1 = [i ** 2 for i in range(6)]
print(list1,type(list1))  # [0, 1, 4, 9, 16, 25] <class 'list'>

ge1 = (i ** 2 for i in range(6))
print(ge1,type(ge1))  # <generator object <genexpr> at 0x101f0c9a8> <class 'generator'>

# 2.访问生成器中的元素
# a.next()
print(next(ge1))
print(next(ge1))
print(next(ge1))
print(next(ge1))
print(next(ge1))
print(next(ge1))
# 注意:如果生成器中的元素全部获取完毕,继续获取,则会报错StopIteration
# print(next(ge1))


# b.for
# for n in ge1:
#     print(n)

# c.list()
# print(list(ge1))

# 3.定义方式二
# a
# return表示函数的返回值
def test1():
    return 10
r1 = test1()
print(r1,type(r1))   # 10 <class 'int'>

# b.
# 注意:只要在函数内部出现yield关键字,则该函数表示一个函数生成器,yield关键字后面的数据将是生成器中的元素
def test2():
    yield 10
r2 = test2()
print(r2,type(r2))   # <generator object test2 at 0x10a379a20> <class 'generator'>
print(next(r2))


# c.
def test3():
    yield 10
    yield 20
    yield 30
r3 = test3()
# for n in r3:
#     print(n)

# d.
def test4(n):
    for i in range(n):
        yield i ** 2
# 获取一个生成器中的4个元素
r4 = test4(10)
print(next(r4))
print(next(r4))
print(next(r4))
print(next(r4))

# 分别获取4个生成器的第0个元素
print(next(test4(5)))
print(next(test4(5)))
print(next(test4(5)))
print(next(test4(5)))

# 注意:函数生成器每调用一次,都表示生成了一个新的生成器

二、可迭代对象和迭代器【面试题】

"""
【面试题】简述可迭代对象和迭代器之间的区别和联系
区别:
    可迭代对象:Iterable,可以直接作用于for循环的对象【可以使用for循环遍历其中元素的对象】
        如:list,tuple,dict,set,str,range(),generator等
    迭代器:Iterator,可以直接作用于for循环,或者可以通过next()获取下一个元素的对象
        如:generator
联系:
    迭代器一定是可迭代对象,但是可迭代对象不一定是迭代器
    可以通过系统功能iter()将不是迭代器的可迭代对象转换为迭代器
"""

from collections import  Iterable,Iterator


# isinstance(变量,类型):判断一个变量是否是指定的数据类型

# 1
print(isinstance([3,4],Iterable))
print(isinstance((3,4),Iterable))
print(isinstance({'a':10},Iterable))
print(isinstance({3,4},Iterable))
print(isinstance("fajg",Iterable))
print(isinstance((i for i in range(3)),Iterable))
print(isinstance(range(3),Iterable))

print("*" * 10)

# 2.
print(isinstance([3,4],Iterator))
print(isinstance((3,4),Iterator))
print(isinstance({'a':10},Iterator))
print(isinstance({3,4},Iterator))
print(isinstance("fajg",Iterator))
print(isinstance(range(3),Iterator))
print(isinstance((i for i in range(3)),Iterator))

print("*" * 10)

# 3.
print(isinstance(iter([3,4]),Iterator))
print(isinstance(iter((3,4)),Iterator))
print(isinstance(iter({'a':10}),Iterator))
print(isinstance(iter({3,4}),Iterator))
print(isinstance(iter("fajg"),Iterator))
print(isinstance(iter(range(3)),Iterator))

三、装饰器【重点掌握】

1.基本使用
#1.概念
"""
已知一个函数,如果需要给该函数增加新的功能,但是不希望修改原函数,
在Python中,这种在代码运行期间动态执行的机制被称为装饰器【decorator】
装饰器的作用:为已经存在的函数或类添加额外的功能
装饰器的本质:实际上就是一个闭包,内部函数访问外部函数中的变量【函数】
"""

# 1.闭包
def func1(a):
    def func2():
        print(a)
    func2()
func1(4)

def func1(a):
    def func2():
        print(a)
    return func2
f = func1(23)
f()

# 2.基本语法:原函数没有参数
# 需求:给test函数增加新的功能,但是不能修改test
def test():                                             # 1     11
    print("拼搏到无能为力,坚持到感动自己")

# 装饰器的书写步骤
# a.书写闭包
# b.给外部函数设置参数,该参数表示需要被装饰的函数
def outter1(func):                                      # 2     4
    print("outter~~~11111")
    def inner1():                                       # 5     9
        print("inner~~~11111")
        # d.调用原函数
        func()                  # test()                # 10
        # e.增加新的功能
        print("new~~~~")                                # 12
    return inner1                                       # 6
# c.调用外部函数
f1 = outter1(test)   # func--->test    f1---->inner1        # 3   7
# f.调用内部函数
f1()                    # 8   13


outter1(test)()


print("*" * 30)

# 3.原函数有参数
# 需求:给下面的函数增加新的功能,该功能可以做年龄的校验,如果为负数,则变成相反数
def  get_age(age):
    print(f"年龄:{age}")

def wrapper1(func):
    def check_age(n):
        # 增加新的功能:校验年龄
        if n < 0:
            n = -n
        # 调用原函数
        func(n)   # get_age()

    return check_age

f1 = wrapper1(get_age)      # func --->get_age   f1--->check_age
f1(-20)  # check_age()
f1(10)

# 注意:如果原函数有参,在内部函数中增加功能的时候,
# 如果需要对原函数的参数进行相应的运算,则需要给装饰器的内部函数设置参数

print("*" * 50)

# 4.@xxx,xxx表示装饰器的外部函数的函数名,只需要将@xxx作用于指定的函数,则该装饰器可以装饰指定的函数
# 注意1:使用@xxx的方式进行装饰,则装饰器必须先存在,然后才能使用
# 注意2:@xxx只会对就近的函数起到装饰作用
def wrapper2(func):
    print("外部函数被调用了~~~~~")
    def check_age(n):
        print("内部函数被调用了~~~~")
        # 增加新的功能:校验年龄
        if n < 0:
            n = -n
        # 调用原函数
        func(n)
    return check_age
@wrapper2     # 调用外部函数,f1 = wrapper2(get_age)
def  get_age(age):
    print(f"年龄:{age}")

get_age(-20)  # 调用内部函数,f1(-20)

"""
工作原理:
    @wrapper2:相当于调用装饰器的外部函数,将原函数传参给func,同时将内部函数的引用返回,原函数的函数名指向内部桉树
    get_age(-20) :调用的是装饰器的内部函数

"""

# 练习【面试题】:书写一个装饰器,统计一个函数的执行时间
import  time
print(time.time())  # 时间戳:获取当前时间距离1970.1.1 00:00:00的秒数
# a.
def test():
    for i in range(100000):
        pass

def wrapper(func):
    def get_time():
        # 开始时间
        start = time.time()
        # 调用原函数
        func()
        # 结束时间
        end = time.time()
        return round(end - start,4)
    return get_time

f = wrapper(test)
print(f())

# b
def wrapper11(func):
    def get_time():
        # 开始时间
        start = time.time()
        # 调用原函数
        func()
        # 结束时间
        end = time.time()
        return round(end - start,4)
    return get_time
@wrapper11
def test():
    for i in range(100000):
        pass
print(test())
2.进阶使用
# 一、基本使用
# 1.
def test():
    print("11111")

def outter(func):
    def inner():
        func()
        print("new~~~~~")
    return inner
f = outter(test)
f()

# 2.推荐使用
def wrapper(func):
    def inner():
        func()
        print("new~~~222")
    return inner
@wrapper    # 相当于 text = wrapper(text)
def text():
    print("2222")
text()   # 调用inner

print("*" * 30)

# 二、进阶使用
# 1.同一个装饰器装饰多个函数
# 特点:给多个不同的函数增加同一个新的功能,为了满足不同函数的需求,装饰器的内部函数设置不定长参数
def wrapper1(func):
    def inner(*args,**kwargs):   # 打包
        func(*args,**kwargs)    # 拆包
        print("new~~~~")
    return inner
@wrapper1
def test1():
    print("test~~1111")
test1()

@wrapper1
def test2(a):
    print("test~~222",a)
test2(3)

@wrapper1
def test3(a,b,c):
    print("test~~3333",a,b,c)
test3(3,4,5)

# 【面试题】书写一个装饰器,可以统计任意一个函数的执行时间
import  time
def wrapper(func):
    def get_time(*args,**kwargs):
        start = time.time()
        func(*args,**kwargs)
        end = time.time()
        return round(end - start,5)
    return get_time
@wrapper
def test2():
    return "abc"
t = test2()
print(t)

print("*" * 30)


# 2.【面试题】多个装饰器装饰同一个函数
# 特点:给同一个函数同时增加多个新的功能
def wrapper1(func1):
    def inner1(*args,**kwargs):
        print("第1个装饰器~~~~~start")
        func1(*args,**kwargs)
        print("第1个装饰器~~~~~end")
    return inner1
def wrapper2(func2):
    def inner2(*args,**kwargs):
        print("第2个装饰器~~~~~start")
        func2(*args,**kwargs)
        print("第2个装饰器~~~~~end")
    return inner2
def wrapper3(func3):
    def inner3(*args,**kwargs):
        print("第3个装饰器~~~~~start")
        func3(*args, **kwargs)
        print("第3个装饰器~~~~~end")
    return inner3

@wrapper1
@wrapper2
@wrapper3
def test():
    print("test~~~~~~~~~~~~")
test()   # inner1()

"""
@wrapper3
def test():
    pass
    
工作原理:test原---》func3    test--->inner3

@wrapper2
@wrapper3
def test():
    pass

工作原理:inner3---->func2    test---->inner2

@wrapper1
@wrapper2
@wrapper3
def test():
    pass
     
工作原理:inner2--->func1     test----->inner1
"""
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值