@[toc]
1. 装饰器
1.1 装饰器的引入(一)
① 装饰器引入过程
def func():
pass
v = 10
v = func
print(v)
def base():
print('base')
def bar():
print('bar')
bar = base
bar()
'''
base
'''
def func():
def inner():
pass
return inner
v = func()
print(v)
def func(arg):
def inner():
print(arg)
return inner
v1 = func(1)
v2 = func(2)
def func(arg):
def inner():
arg()
return inner
def f1():
print(123)
v = func(f1)
v()
'''
123
'''
def func(arg):
def inner():
arg()
return inner
def f1():
print(123)
return 456
v = func(f1)
result = v()
print(result)
'''
123
None
'''
def func(arg):
def inner():
return arg()
return inner
def f1():
print(123)
return 456
v = func(f1)
result = v()
print(result)
'''
123
456
'''
def func():
print(123)
v = func
func = 456 # 修改func,但是v还是执行func函数的地址
1.2 装饰器的引入(二)
① 引入装饰器
def func(arg):
def inner():
return arg()
return inner
def index():
print(123)
return 456
v = index()
def func(arg):
def inner():
return arg()
return inner
def index():
print(123)
return 456
v2 = func(index) # v2是inner函数
index = 789
v3 = v2()
def func(arg):
def inner():
return arg()
return inner
def index():
print(123)
return 456
v4 = func(index)
def func(arg):
def inner():
return arg()
return inner
def index():
print(123)
return 456
index = func(index)
index()
def func(arg):
def inner():
print('before')
v = arg()
print('after')
return v
return inner
def index():
print(123)
return 456
index = func(index)
index()
def func(arg):
def inner():
print('before')
v = arg()
print('after')
return v
return inner
'''
def index():
print(123)
return 456
index = func(index)
index()
'''
# 第一步:执行func函数并将下面的函数当作参数传递,相当于func(index)
# 第二部:将func(index)的返回值重新赋值给下面的函数名,相当于index = func(index)
def index():
print(123)
return 456
print(index)
v = index()
print(v)
print()
@func
def index():
print(123)
return 456
print(index)
v = index()
print(v)
'''
123
456
.inner at 0x0000022A5490C840>
before
123
after
456
'''
② 装饰器的目的
装饰器:在不过改变原函数内部代码的基础上,在函数执行前后自定义功能(在原函数执行之前和之后自动执行某个功能)。装饰器本质上是一个函数,而且使一个而双层函数。
③ 如何写装饰器
def x(fun): # 必须有一个参数
def y():
ret = fun()
return ret
return y
@x
def index():
'''
被装饰的函数
:return:
'''
pass
# 执行函数自动触发装饰器,函数返回值也能拿到
index()
v = index()
print(v)
④ 装饰器编写格式
def 外层函数(参数):
def 内层函数():
return 参数()
return 内层函数
⑤ 装饰器应用格式
@外层函数
def 需要加装饰器的函数():
pass
需要加装饰器的函数()
⑥ 为什么要加入args和wargs
原函数中有参数的情况下,需要在内部函数中加入args和**wargs,可以接收任意参数,
def 外层函数(参数):
def 内层函数(*args,**kwargs):
return 参数(*args,**kwargs)
return 内层函数
@外层函数
def index(1,['thanlon'],{'k1':'v1','k2':'v2'}):
pass
1.3 装饰器需要注意的
① 统一参数
统一参数的目的是为了给原函数(加装饰器的函数)传参,没有统一参数:
def x(func):
'''
:param func: index()
:return:inner
'''
def inner(a,b):
data = func()
return data
return inner
@x
def index():
pass
index(1, 2)
统一参数:
def x(func):
'''
:param func: index()
:return:inner
'''
def inner(a, b):
data = func(a, b)
return data
return inner
@x
def index(a, b):
return a + b
v = index(1, 2)
print(v)
如果给不同参数的函数统一装饰器,如何做?
def x(func):
'''
:param func: index()
:return:inner
'''
def inner(*args, **kwargs):
data = func(*args, **kwargs)
return data
return inner
@x
def index():
pass
print(index())
@x
def index(a, b):
return a + b
print(index(1, 2))
@x
def index(a, b, c):
return a * b * c
print(index(1, 2, 3))
'''
None
3
6
'''
② 原函数执行前后执行其它操作
- 基本格式:
def x(func):
def inner(*args, **kwargs):
print('调用原函数之前的操作')
data = func(*args, **kwargs) # 执行原函数并且获取返回值
print('调用原函数之后的操作')
return data
return inner
@x
def index():
return 'thanlon'
- 在原函数执行之前
练习1:请为以下函数编写装饰器,添加上装饰器后可以实现:执行read_ userinfo函数时,先检查文件路径是否存在,如果不存在则输入文件路径不存在,并且不再执行read_userinfo函数体中的内容,再将content变量赋值None,
def read_userinfo(path):
file_obj = open(path, mode='r', encoding='utf-8')
data = file_obj.read()
file_obj.close()
return data
content = read_userinfo('E:\pycharmProjects\practice\log.txt')
为代码加装饰器:
import os
def wrapper(func):
def inner(*args, **kwargs):
# 检查路径是否存在
if not os.path.exists(args[0]):
print('文件路径不存在')
return None
result = func(*args, **kwargs)
return result
return inner
@wrapper
def read_userinfo(path):
file_obj = open(path, mode='r', encoding='utf-8')
data = file_obj.read()
file_obj.close()
return data
content = read_userinfo('E:\pycharmProjects\practice\log.txt')
print(content)
- 在原函数执行之后
练习2:请为以下函数编写一个装饰器,添加装饰器后可以实现:将被执行的函数执行5次,将每次执行函数的结果按照顺序放在列表中,最终返回列表:
import random
def wrapper(func):
def inner(*args, **kwargs):
lst = []
for i in range(5):
data = func(*args, **kwargs)
lst.append(data)
return lst
return inner
@wrapper
def func():
return random.randint(1, 4)
result = func()
print(result)
'''
[2, 3, 3, 3, 4]
'''
③ 装饰器的建议写法(重要)
def x(func):
def inner(*args, **kwargs):
data = func(*args, **kwargs)
return data
return inner
1.4 装饰器的应用
① 计算函数执行时间
- 不适用装饰器:代码量大
# coding:utf-8
'''
没有使用装饰器
'''
import time
def func():
time.sleep(3)
def func2():
time.sleep(3)
def func3():
time.sleep(3)
start_time = time.time()
func()
end_time = time.time()
print(end_time - start_time)
start_time = time.time()
func2()
end_time = time.time()
print(end_time - start_time)
start_time = time.time()
func3()
end_time = time.time()
print(end_time - start_time)
'''
3.0121190547943115
3.0035953521728516
3.010974407196045
'''
② 使用装饰器:统一批量在函数之前和函数之后做操作
# coding:utf-8
'''
没有使用装饰器
'''
import time
def wrapper(args):
def inner():
start_time = time.time()
v = args()
end_time = time.time()
print(end_time - start_time)
return v
return inner
@wrapper
def func():
time.sleep(3)
@wrapper
def func2():
time.sleep(3)
@wrapper
def func3():
time.sleep(3)
func()
func2()
func3()
1.5 带参数的装饰器(没有普通装饰器重要)
① 带参数的装饰器应用
flask框架、django缓存、写装饰器实现被装饰的函数要执行N次。
② 带参数的装饰器示例
'''
带参数的装饰器
'''
def x(name):
print(name)
def wrapper(func):
print('wrapper')
def inner(*args, **kwargs):
data = func(*args, **kwargs) # 执行原函数并获取返回值
return data
return inner
return wrapper
'''
1. 执行x(9),得到返回值wrapper
2. 把index函数当作参数传入wrapper函数[wrapper(index)],并执行wrapper函数得到inner,然后index = inner
'''
@x('thanlon') # index = x(9)(index)
def index():
pass
# index() # 执行inner函数,也就是执行原函数index
# v = index() # 获取index函数的返回值
'''
thanlon
wrapper
'''
③ 带参数的装饰器练习(面试题用笔写)
练习1:写一个带参数的装饰器,实现参数是多少被装饰的函数就要执行多少次,把每次执行的结果添加到列表中,最终返回列表。
'''
练习:写一个带参数的装饰器,实现参数是多少被装饰的函数就要执行多少次,把每次执行的结果添加到列表中,最终返回列表。
'''
def x(counter):
def wrapper(func):
def inner(*args, **kwargs):
lst = []
for i in range(counter):
data = func(*args, **kwargs)
lst.append(data)
return lst
return inner
return wrapper
@x(6)
def index():
return 666
v = index()
print(v)
'''
[666, 666, 666, 666, 666, 666]
'''
练习2:写一个带参数的装饰器,实现参数是多少被装饰的函数就要执行多少次,并返回最后依次执行的结果。(面试题)
'''
练习:写一个带参数的装饰器,实现参数是多少被装饰的函数就要执行多少次,并返回最后依次执行的结果。
'''
def x(counter):
def wrapper(func):
def inner(*args, **kwargs):
for i in range(counter):
data = func(*args, **kwargs)
return data
return inner
return wrapper
@x(6)
def index():
return 666
v = index()
print(v)
'''
666
'''
2. 推导式
2.1 列表推导式
① 列表推导式的作用
方便生成一个列表
② 基本格式
v = [i for in 可迭代对象]
v = [i for in 可迭代对象 if 条件](条件为True才进行append)
③ 列表推导式例子
v = [i for i in 'thanlon']
# coding:utf-8
v = [i for i in 'thanlon']
print(v)
'''
['t', 'h', 'a', 'n', 'l', 'o', 'n']
'''
v = [i+100 for i in range(10)]
# coding:utf-8
v = [i+100 for i in range(10)]
print(v)
'''
[100, 101, 102, 103, 104, 105, 106, 107, 108, 109]
'''
v = ['thanlon' if i > 5 else 'kiku' for i in range(10)]
# coding:utf-8
v = ['thanlon' if i > 5 else 'kiku' for i in range(10)]
print(v)
'''
['kiku', 'kiku', 'kiku', 'kiku', 'kiku', 'kiku', 'thanlon', 'thanlon', 'thanlon', 'thanlon']
'''
# coding:utf-8
def func():
return 1
v = [func for i in range(10)]
print(v)
'''
[, , , , , , , , , ]
'''
# coding:utf-8
v = [lambda: 100 for i in range(10)]
ret = v[3]()
print(ret)
'''
100
'''
# coding:utf-8
def func():
return i
v = [func for i in range(10)]
ret = v[4]()
print(ret)
'''
9
'''
# coding:utf-8
v = [lambda :i for i in range(10)]
ret = v[4]()
print(ret)
'''
9
'''
④ 列表推导式筛选
# coding:utf-8
v = [i for i in range(10) if i > 5]
print(v)
'''
[6, 7, 8, 9]
'''
⑤ 面试题一(新浪微博面试题)
# coding:utf-8
'''
新浪面试题:v是什么?v[0](2)的结果是什么?
'''
v = [lambda x: x + i for i in range(10)] # 新浪面试题
# v是什么?一个包含对象的列表
print(v)
'''
[. at 0x00000217B0BCC7B8>, . at 0x00000217B0BCC8C8>, . at 0x00000217B0BCC840>, . at 0x00000217B0BCC950>, . at 0x00000217B0BCC9D8>, . at 0x00000217B0BCCA60>, . at 0x00000217B0BCCAE8>, . at 0x00000217B0BCCB70>, . at 0x00000217B0BCCBF8>, . at 0x00000217B0BCCC80>]
'''
print(v[0](2)) # 9+11
⑥ 面试题二
# coding:utf-8
def num():
return [lambda x: i * x for i in range(4)]
print(num()) # [函数,函数,函数,函数]
print([m(2) for m in num()])
'''
[.. at 0x00000274ECEFC8C8>, .. at 0x00000274ECEFC840>, .. at 0x00000274ECEFC950>, .. at 0x00000274ECEFC9D8>]
[6, 6, 6, 6]
'''
2.2 集合推导式
集合推导式与列表推导式相似,将 [ ] 号换成 { }。
v = { i for i in 'thanlon'}
print(v)
2.3 字典推导式
v = {'k' + str(i): i for i in range(10)}
print(v)
2.4 生成器推导式(面试题)
对于列表:v = [i for i in range(10)] # 列表推导式,立即循环创建所有元素,等价于:
# v = [i for i in range(10)] # 列表推导式,立即循环创建所有元素
def func():
result = []
for i in range(10):
result.append(i)
return result
v = func()
对于生成器:
v = (i for i in range(10))
print(v)
'''
at 0x0000027472A85570>
'''
v = (i for i in range(10)) # 生成器推导式,创建一个生成器,循环生成器一个一个创建元素,等价于:
def func():
for i in range(10):
yield i
v = func()
print(v)
'''
at 0x0000027472A85570>
'''
for item in v:
print(item)
面试题: 请比较[i for i in range(10)]和(i for i in range(10))的区别?
[i for i in range(10)]是列表推导式,内部生成列表;(i for i in range(10))是生成器推导式,一个生成生成器。
① 示例1
# v = [lambda: i for i in range(10)]
# for item in v:
# print(item())
'''
等价于下面的
'''
def func():
result = []
for i in range(10):
def f():
return i
result.append(f)
return result
v = func() # for循环执行完毕,但f函数没有执行,f执行时,自己没有i向上一级找i,i = 9
for item in v:
print(item())
② 示例2
# v = (lambda: i for i in range(10))
# for item in v:
# print(item())
'''
等价于下面的
'''
def func():
for i in range(10):
def f():
return i
yield f
v = func() # 生成器,内部代码没有执行
for item in v: # 生成器执行循环的时候才执行
print(item())
'''0
1
2
3
4
5
6
7
8
9
'''
2.5 推导式总结
列表推导式常用一些,注意字典推导式写法。