Python基础学习(13)匿名函数 内置函数Ⅱ 闭包
一、今日内容大纲
- 匿名函数 lambda
- 内置函数 Ⅱ
- 闭包
二、匿名函数 lambda
简单来说,匿名函数就是是用一句话实现函数的功能,是一种比较简单的函数;比如我们分别利用匿名函数方法和普通函数方法构造一个同样功能的函数:
# 构建普通函数
def func(a, b):
return a + b
# 构建匿名函数,调用方法和普通函数一致
func1 = lambda a, b: a + b
# Example 1:
# 接收一个可切片的数据,返回索引为0和2对应的元素(元组形式)
func = lambda elements: (elements[0], elements[2])
# 接收两个int参数,将较大的数据返回
func = lambda a, b: a if a > b else b
三、内置函数 Ⅱ
这次介绍一些相对来说比较重要的内置函数:
-
print(self, *args, sep=' ', end=' ', file=None)
:屏幕输出其中:
sep
全称为separation
,用来定义多个变量之间的分隔字符;end
,用来定义print()
函数输入结尾的字符。# sep:全称 separation ,分隔符 # end:末尾 print('test_1', 'test_2', sep='+') # test_1+test_2 print('test_1', 'test_2', end='***end***') # test_1 test_2***end***
-
int()
:passstr()
:passbool()
:passset()
:passlist()
:将一个可迭代对象转换为列表tuple()
:将一个可迭代对象转换为元组dic()
:通过相应的方式构建字典# list() l1 = list('das') print(l1) # # ['d', 'a', 's'] # dict()创建修改字典的几种方式 dic = dict([(1, 'one'), (2, 'two')]) dic = dict(one=1, two=2) dic = dict.fromkeys('abc', 10) dic = dic.update(ds='sa') # 另有字典的推导式方式
-
abs()
:全称absolute
,返回数字的绝对值print(abs(-6)) # 6
-
sum()
:需要传入可迭代对象,返回和,可以定义第二个参数作为起始值l1 = [i for i in range(10)] # print(sum('123')) # TypeError: unsupported operand type(s) for +: 'int' and 'str' # print(sum(1,3)) # TypeError: 'int' object is not iterable print(sum(l1)) # 45 print(sum(l1, 100)) # 145
-
reversed()
:将可迭代对象翻转后转化为迭代器返回l1 = [i for i in range(10)] # l1.reverse() # list.reverse()是列表拥有的方法,并非内置函数,将原列表反转,无返回值。 # print(l1) # [9, 8, 7, 6, 5, 4, 3, 2, 1, 0] obj = reversed(l1) print(obj) # <list_reverseiterator object at 0x000001AF2F9CE400> print(list(obj)) # [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
-
zip()
:拉链法,返回一个迭代器l1 = [1, 2, 3, 4, 5] tu1 = ('taibia', 'bge', 'degang') s1 = 'abcd' obj = zip(l1, tu1, s1) print(obj) # <zip object at 0x0000019E5F121608> # print(list(obj)) # [(1, 'taibia', 'a'), (2, 'bge', 'b'), (3, 'degang', 'c')] for i in obj: print(i) # (1, 'taibia', 'a') # (2, 'bge', 'b') # (3, 'degang', 'c')
-
min(*args, key=None)
:返回最小值,参数可以为可迭代对象,也可以是多个变量,可以利用key
定义函数取特定的最小值max()
:与min()
使用方法一致,返回最大值# 取最小绝对值 # 普通方法 l2 = [] func = lambda a: abs(a) for i in l1: l2.append(func(i)) print(min(l2)) # 1 # 利用key参数简化返回最小绝对值 # 传入key参数之后,运行时会自动将可迭代对象的每个元素传入key所指代的函数中并返回比较大小,min函数返回的值为原可迭代对象中元素。 print(min(l1, key=abs)) # 1
# 利用min()求值最小的键值,min()默认会比较键的大小 dic = {'a': 3, 'b': 2, 'c': 1} # def func(a): # 省略使用匿名函数 # return dic[a] print(min(dic, key=lambda a: dic[a])) # c
# Example 1: 利用min()求年龄最小的老师 l2 = [('太白', 18), ('alex', 73), ('wusir', 35), ('口天吴', 41)] print(min(l2, key=lambda tu: tu[1])) # ('太白', 18)
-
sorted(*args, **kwargs)
:返回顺序(默认从小到大)的可迭代对象,同min()
一样,也可以加key
参数定制排序规则。l1 = [22, 33, 1, 2, 4, 5] l2 = sorted(l1) print(l1) # [22, 33, 1, 2, 4, 5] print(l2) # [1, 2, 4, 5, 22, 33] # 利用key参数定制排序 l2 = [('大壮', 76), ('雪飞', 70), ('纳钦', 94), ('张珵', 98), ('b哥', 96)] # print(sorted(l2)) # [('b哥', 96), ('大壮', 76), ('张珵', 98), ('纳钦', 94), ('雪飞', 70)] print(sorted(l2, key=lambda tu: tu[1])) # [('雪飞', 70), ('大壮', 76), ('纳钦', 94), ('b哥', 96), ('张珵', 98)]
-
filter()
:返回的是一个迭代器,类似于列表推导式的筛选模式。l1 = [2, 3, 4, 5, 6, 7] # 利用列表推导式筛选列表中大于3的元素 print([i for i in l1 if i > 3]) # 返回的是列表 [4, 5, 6, 7] # 利用filter()筛选 ret = filter(lambda x: x > 3, l1) # 返回的是迭代器 print(ret) # <filter object at 0x00000184F3B4E898> print(list(ret)) # [4, 5, 6, 7]
-
map()
:返回的是一个迭代器,类似于列表推导式的循环模式。print([i ** 2 for i in range(1, 6)])# 返回的是列表[1, 4, 9, 16, 25] ret = map(lambda x:x ** 2, range(1, 6)) # 返回的是迭代器 print(ret) # <map object at 0x0000027D2B6EE630> print(list(ret)) # [1, 4, 9, 16, 25]
-
reduce()
:用于累积计算,返回一个最终值,在Python 2x
中是内置函数,在Python 3x
中是模块中内容。from functools import reduce def func(x, y): ''' Run 1: x = 1 y = 2 x * 10 + y = 12 Run 2: x = 12 y = 3 x * 10 + y = 123 Run 3: x = 123 y = 4 x * 10 + y = 1234 ''' return x * 10 + y l = reduce(func, [1, 2, 3, 4]) print(l)
四、闭包
-
什么是闭包
首先引入一个概念:平均收盘价,即某个商品从出现开始,每天记录当天的价格并求取平均价格。
比如大众出了一款新车:小白轿车。
第一天价格为:100000 元 平均收盘价为: 100000 元
第二天价格为:110000 元 平均收盘价为:(100000 + 110000) / 2 元
第三天价格为:120000 元 平均收盘价为:(100000 + 110000 + 120000) / 3 元
利用
Python
求取它的平均收盘价,给出了以下三个方案:# 方案一 l1 = [] # 全局变量,数据不安全 def make_averager(new_value): l1.append(new_value) total = sum(l1) averager = total / len(l1) return averager print(make_averager(100000)) # 100000.0 print(make_averager(110000)) # 105000.0 # 很多代码。。。 # l1.append(666) # 第三次结果会变成82666.5 print(make_averager(120000)) # 110000.0 # 方案二:数据安全,l1不可以是全局变量 def make_averager(new_value): l1 = [] # l1在临时变量,计算结果有误 l1.append(new_value) total = sum(l1) averager = total / len(l1) return averager print(make_averager(100000)) # 100000.0 print(make_averager(110000)) # 110000.0 # 很多代码。。。 print(make_averager(120000)) # 120000.0 # 方案三:闭包 def make_averager(): l1 = [] # averager函数的作用域延伸到包含自由变量l1与其绑定,也就是说, # 每次调用averager函数时,都可以引用到这个自由变量了,这就是闭包 def averager(new_value): l1.append(new_value) # print(l1) # Run 1:[100000] Run 2:[100000, 110000] Run 2:[100000, 110000, 120000] total = sum(l1) return total / len(l1) return averager # 返回内部函数averager的内存地址 avg = make_averager() # averager # 因为闭包现象,自由变量 l1 一直没有消失 print(avg(100000)) # 100000.0 print(avg(110000)) # 105000.0 # 很多代码。。。 print(avg(120000)) # 110000.0
-
闭包的定义:闭包只存在于嵌套函数中,内层函数对外层函数非全局变量的引用(不可变对象可以依靠
nonlocal
改变)这时就会形成闭包。被引用的非全局变量也称作自由变量,这个自由变量会与内层函数产生一个绑定关系,使自由辩论不会在内存中消失。 -
闭包的作用:保证数据的安全,自由变量除了闭包内的内层函数,没有对象可以利用与改变它。
-
判断一个嵌套函数是否是闭包
- 闭包只能存在于嵌套函数中。
- 内层函数对外层函数非全局变量的引用,这时就会形成闭包。
- 可以利用函数的
__code__.co_freevars
属性查看函数的自由变量,从而判断一个嵌套函数是否是闭包。
# Example 1: True def wrapper(): a = 1 def inner(): print(a) return inner ret = wrapper() # Example 2: False a = 2 def wrapper(): def inner(): print(a) return inner ret = wrapper() # Example 3: True def wrapper(a, b): # 传入变量a和b,相当于在函数内部创建了两个临时变量a和b def inner(): print(a) print(b) return inner a = 2 b = 3 ret = wrapper(a, b) # 用代码判断闭包,查看函数的自由变量:函数的__code__方法 def wrapper(a, b): def inner(): print(a) print(b) return inner a = 2 b = 3 ret = wrapper(a, b) print(ret.__code__.co_freevars) # ('a', 'b') free variables