一、生成器【重点掌握】
# 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
"""