一木.溪桥 在Logic Education跟Amy学Python
逻辑教育 :https://logicedu.ke.qq.com
12期:Python基础课
一木.溪桥学Python-10:函数闭包、装饰器、推导式
日期:2021年1月6日
学习目标:
- 函数闭包
- 装饰器
- 推导式
学习内容:
函数闭包
- 闭包的定义需要满足以下三个条件:
在一个外函数中定义了一个内函数
内函数里运用了外函数的临时变量
并且外函数的返回值是内函数的引用
def test(number): # number 形参 临时变量
print("--1--")
def test_in(number_in):
print(number_in)
print("--2--")
return number_in + number
print("--3--")
return test_in
# test()执行完毕时,输出1,3。并且函数里面的变量会被释放掉(number)
res = test(30) # res = test_in
res1 = res(25) # test_in()
print(res1) # 45,说明在外层函数执行完毕时,number并没有被释放,而是继续给内层函数使用。
Run:
–1--
–3--
25
–2--
55
- 总结:闭包它是一种现象
一般情况下,外函数执行完毕时,临时变量会被释放。
但此时,外函数发现自己的临时变量会在将来被使用,
所以外函数结束的时候,在返回内函数引用的同时,将外函数的临时变量与内函数进行绑定。
这也是为什么当外函数结束,但内函数仍然可以使用外函数临时变量的原因。
eg.由闭包引出装饰器的案例
import time # python内置模块,时间模块
# 计算时间得函数
def calcu_time(func):
start = time.time()
func()
end = time.time()
print(f"spend {end - start}")
def test1():
print("--test1--")
time.sleep(1.5)
"""
sleep(seconds)
Delay execution for a given number of seconds. The argument may be
a floating point number for subsecond precision.
"""
def test2():
print("--test2--")
time.sleep(1)
calcu_time(test1)
calcu_time(test2)
"""
就是在不改变函数源代码得情况下为函数添加新得功能
"""
Run:
–test1–
spend 1.500859022140503
–test2–
spend 1.0009346008300781
装饰器
- 装饰器 (@) 是一种语法糖,主要用于在函数或类的基础上添加一些可重用的额外功
能。从应用开发的角度来看的话,我们使用装饰器来对我们的应用代码进行功能性
扩展和包装,以提高代码的可重用性和可维护性。 - 装饰器的应用
日志记录
调用跟踪管理及参数验证
在 Web 应用中进行登录验证或路由注册
性能优化中记录任务执行时间
# 需要给各个函数添加上打印hello world得功能
def print_hw(f):
print("hello world")
return f
@print_hw # @装饰器函数名称 test2 = print_hw(test)
def test():
sum_li = sum([12, 3, 4])
print(sum_li)
return sum_li
@print_hw
def test2():
print("我是老amy")
# test2 = print_hw(test) # test函数引用作为实参 test2 = f = test
# test2() # test2() = f() = test()
test()
test2()
"""
注意:
1. test()函数未调用得时候,装饰器就已经执行
"""
Run:
hello world
hello world
19
大家好!
我是老amy
大家好!!!
eg. 装饰器应用例–计算时间得函数
# 计算时间得函数
def calcu_time(func):
def test_in(): # 1.外函数里面有内函数
start = time.time()
func() # test1() # 2.内函数引用了外函数得临时变量
end = time.time()
print(f"spend {end - start}")
return test_in # 3.内函数的引用作为外函数的返回值
@calcu_time # test = calcu_time(test1)
def test1():
print("--test1--")
time.sleep(2)
@calcu_time
def test2():
print("--test2--")
time.sleep(2)
# test = calcu_time(test1) # test = test_in
# test() # test_in()
# test = calcu_time(test2) # test = test_in
# test() # test_in()
test1()
test2()
"""
此处,形成闭包的现象。
1.嵌套函数
2.内层函数引用外层函数变量-->函数名本质也是变量
3.内函数的引用作为外层函数的返回值
"""
Run:
–test1–
spend 2.000833511352539
–test2–
spend 2.001018762588501
推导式
推导式介绍
Python 中有一种特有的语法,就是推导式(又称为解析式)。推导式是可以从一个数据序列构建另一个新的数据序列的结构体。
三种推导:
- 列表(list)推导式
- 字典(dict)推导式
- 集合(set)推导式
列表生成案例分析对比:
"""
有列表如:li = [6, 2, 6, 7, -15, 8, -17, -10, -15, -4]。
需求:将li列表 <0 的数进行平方 生成新列表
"""
# li = [6, 2, 6, 7, -15, 8, -17, -10, -15, -4]
# li1 = []
#
# for i in li:
# if i < 0:
# i = i**2
# li1.append(i)
#
# print(li1)
# 将小于0的过滤出来 filter()
# 将过滤出来的元素 映射做平方操作
# fil = list(filter(lambda x: x < 0, li))
# print(list(map(lambda x: x**2, fil)))
# 注意:此处不是三目运算符!!!
# li2 = [i**2 for i in li if i < 0]
# print(li2)
# for i in "123":
# for j in "abc":
# print(i+j)
列表推导式
- 格式
[out_express for out_express in input_list]
[out_express for out_express in input_list if out_express_condition]
[i for row in matrix for i in row]
# 列表推导式的嵌套
print([i+j for i in "123" for j in "abc"])
Run:
[‘1a’, ‘1b’, ‘1c’, ‘2a’, ‘2b’, ‘2c’, ‘3a’, ‘3b’, ‘3c’]
字典推导式
- 格式
{out_exp_key: out_exp_value for out_exp in input_list}
# 实现:以下列表中的元素 与 索引 --> {key:value} 的形式
li = ["age", "name", "gender"]
dic = {i: li.index(i) for i in li}
print(dic)
Run:
{‘age’: 0, ‘name’: 1, ‘gender’: 2}
集合推导式
- 格式
{out_exp_res for out_exp in input_set}
# 实现生成10个1-100之间的元素,进行去重
# 集合推导式
import random
s1 = {random.randint(1, 100) for i in range(10)}
print(s1)
Run:
{96, 65, 67, 38, 80, 81, 18, 82, 20, 63}
- tips:
- 没有元组推导式,(i for i in range(10)) 返回的是 generator object
# 注意:没有元组推导式,而是生成器
tu = (i for i in range(3))
print(tu) # generator
print(type(tu)) # generator
print(tuple(tu)) # 转为tuple类型
Run:
<generator object at 0x0000027F71A6EF10>
<class ‘generator’>
(0, 1, 2)
作业:
作业答案:
题1:
# 作业 1
# 过滤掉该列表 names = ["jerry","hansen","Amy","Wendy","Tom","Bob"]
# 长度小于或等于 3 的字符串列表,并将剩下的转换成大写字母。
names = ["jerry", "hansen", "Amy", "Wendy", "Tom", "Bob"]
new_names = list(filter(lambda x: len(x) > 3, names))
print("题目输出结果是:", list(map(lambda x: x.upper(), new_names)))
- Run:
题目输出结果是: [‘JERRY’, ‘HANSEN’, ‘WENDY’]
题2:
# 作业 2
# 求 (x,y), 其中 x 是 0-5 之间的偶数, y 是 0-5 之间的奇数组成的元组列表。
# 效果如下: [(0, 1), (0, 3), (2, 1), (2, 3), (4, 1), (4, 3)]
tup_x = tuple([i for i in range(0, 5) if i % 2 == 0]) # 生成0-5 之间的偶数元组
tup_y = tuple([i for i in range(0, 5) if i % 2 == 1]) # 生成0-5 之间的奇数元组
print("题目输出结果:", list((i, j) for i in tup_x for j in tup_y))
- Run:
题目输出结果: [(0, 1), (0, 3), (2, 1), (2, 3), (4, 1), (4, 3)]
题3:
# 作业 3
# [ 'Bob', 'JOHN', 'alice', 'bob', 'ALICE', 'James', 'Bob','JAMES','jAMeS' ]
# 该列表很紊乱,实现去重 , 以及将名字格式统一成首字母大写 (str.capitalize())
li = ['Bob', 'JOHN', 'alice', 'bob', 'ALICE', 'James', 'Bob', 'JAMES', 'jAMeS']
print("题目输出结果:", list(set(map(lambda x: x.lower().capitalize(), li))))
- Run:
题目输出结果: [‘Bob’, ‘Alice’, ‘James’, ‘John’]
End !
Best wishes for you!