Python基础之 推导式 与 匿名函数

推导式

推导式( comprehensions ),又称为解析式,是 Python 中的一种独有特性。推导式是可以从一个数据序列构建另一个新的数据序列的结构体。 共有三种推导式:
· 列表推导式
· 字典推导式
· 集合推导式

推导式具有固定的格式,下面以列表推导式为例(也适用于其他推导式):

variable = [out_exp_res for out_exp in input_list if out_exp == 2]

out_exp_res :列表生成元素表达式,可以是有返回值的函数。
for out_exp in input_list :迭代input_list将out_exp传入out_exp_res表达式中。
if out_exp == 2 : 根据条件过滤哪些值可以。

根据推导式的固定格式,下面分别给出三种数据类型的推导式实例。


列表推导式

1. 找出20以内的所有偶数

even_num = [i for i in range(20) if i % 2 == 0]
print(even_num)  # [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

2. 找出10000以内的完全数的平方

完全数是所有真因子(除了它本身的所有约数)之和等于它本身的数。例如6, 1+2+3 = 6。 它的平方就是36。

def is_prefect_number(n):
    cnt = 0
    for i in range(1, n):
        if n % i == 0:
            cnt += i
    if cnt == n:
        return True

def squared(n):
    return n * n

square_prefect_num = [squared(i) for i in range(1, 10000) if is_prefect_number(i)]
print(square_prefect_num)  # [36, 784, 246016, 66064384]

3. 将名单的嵌套列表中含有两个 L(不区分大小写)的名字找出来

names = [['Smith', 'Johnson', ' Williams', 'Jones'], ['Brown', 'Allen',
         'Lee', 'Hall'], ['Anderson', 'King', 'Collins', 'Miller', 'Taylor'], ['Phillips', 'Thompson']]

L_in_name = [name for lst in names for name in lst if name.lower().count('l') == 2]
print(L_in_name)  # [' Williams', 'Allen', 'Hall', 'Collins', 'Miller', 'Phillips']

字典推导式

1. 将字典的 key 与 value 对调

dic = {'a': 1, 'b': 2}
dic_ver = {dic[k]: k for k in dic}
print(dic_ver)  # {1: 'a', 2: 'b'}

2. 合并大小写对应的 value,并将 key 统一小写

dic = {'a': 3, 'b': 7, 'A': 9, 'c': 14, 'B': 1}
dic_merge = {k.lower(): dic.get(k.lower(), 0) + dic.get(k.upper(), 0) for k in dic}
print(dic_merge)  # {'a': 12, 'b': 8, 'c': 14}

集合推导式

集合推导式就是列表推导式的 [] 改成 {} ,只是集合推导式自带去重效果。

1. 求列表中所有数的平方

set_square = {i**2 for i in [-2, -1, 1, 2, 3]}
print(set_square)

匿名函数

匿名函数是为了解决功能简单的需求而设计的一句话函数,在一些特定的情况下使用会更加简洁方便。

def squared(n):
    return n**2
print(squared(2))  # 4

上面是常见的求一个数的平方的函数写法,我们把它换成匿名函数。

squared = lambda n: n**2
print(squared(4))  # 4

观察可得知匿名函数的固定格式为:

函数名 = lambda 参数: 返回值

注:
参数可以拥有多个,多个参数之间用逗号隔开;
匿名函数无论逻辑复杂程度都只能写一行,函数的返回值就是这一行的运行结果。 返回值可以是任意数据类型;
匿名函数和普通函数一样可以通过 函数名(参数) 的方式调用。

通过上面的分析总结,我们知道匿名函数并不是真的匿名,它也是使用函数名来调用。 它的作用只是这样了吗? 这样它存在有什么意义呢? 我们直接用函数不就好了?

其实匿名函数大显身手的地方并不是这里,它在和其他功能函数合作的时候就可以真正的匿名了。例如配合 Python 中的内置函数使用:

1. 配合 map,将两个列表对应位置相加

ret = map(lambda x, y: x+y, [1, 3, 2, 7], [5, 9, 0, 1])
print(list(ret))  # [6, 12, 2, 8] ret是一个map对象,是一个迭代器,需要将它转化为列表

2. 使用 sorted,将字典按照 value 排序

dic = {'A': 2, 'B': 4, 'C': 1, 'D': 9, 'E': 7}
# 将字典转化为一个可迭代对象,每一个item就是一个的元祖,再按照元祖的第二个值(也就是字典的value)进行排序
list_dic = sorted(dic.items(), key=lambda item: item[1])
print(list_dic)

3. 现有两个元祖 ((‘a’), (‘b’)), ((‘c’), (d)),使用匿名函数将其转化为 [{‘a’:‘c’}, {‘b’:‘d’}]。

t1 = (('a'), ('b'))
t2 = (('c'), ('d'))

# 方法1
fuc = lambda x, y: [{i: j} for i, j in zip(x, y)]
print(fuc(t1, t2))

# 方法2
ret = list(map(lambda t: {t[0]: t[1]}, zip(t1, t2)))
print(ret)

# 方法3(不适用匿名函数,使用列表推导式)
ret = [{i: j} for i, j in zip(t1, t2)]
print(ret)

4. 有趣的刁钻小题

def multipliers():
    return [lambda x:i*x for i in range(4)]  
print([m(2) for m in multipliers()])

请问这段代码的运行结果是什么,怎么样才能得到我们想要的结果?

首先揭开谜底运行结果是[6, 6, 6, 6],为什么呢? 请看:

def multipliers():
    return [lambda x:i*x for i in range(4)]  # 1.列表推导式,这里面存放的是四个函数地址,函数为lambda x:i*x
# 2.那么实际上这里就是: return [lambda x: i*x的地址, lambda x: i*x的地址, lambda x: i*x的地址, lambda x: i*x的地址]


print([m(2) for m in multipliers()])  # 3.那么这里就变成了 for m in [lambda x: i*x的地址, lambda x: i*x的地址, lambda x: i*x的地址, lambda x: i*x的地址]
# 4.每一个m都是相同的函数名,传入参数2,这里就有了
# [lambda 2: i*2, lambda 2: i*2, lambda 2: i*2, lambda 2: i*2]
# 此时开始调用lambda函数,找到i的内存地址,发现i==3

那么我们想要结果为[0, 2, 4 6],该怎么做?

将函数中 return 的列表推导式改成生成器表达式就好了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章