29.递归&三元表达式&生成式&匿名函数

1.递归函数

1.1定义
递归:函数在运行过程中直接或间接的调用自己。提供了一种基于函数实现循环。
默认1000层,超出报错,可以设置参数修改层次,某些电脑可能只能达到99?几层。
递归分两部:
1.递推:一层层往下推导结果
2.回溯:依据最后的结果回溯得到最初问题的答案。

递归是要有一定条件的。
1.每次递推之后复杂度相较于上一次一定要有所下降
2.必须要能回溯
1.2案例1
有五个小朋友:
1 2 3 4 5                           count = 5
第一个小朋友说比第二个小朋友大 2      + 2
第二个小朋友说比第三个小朋友大 2      + 2
第三个小朋友说比第四个小朋友大 2      + 2
第四个小朋友说比第五个小朋友大 2      + 2
第五个小朋友18                      count return 18

image-20211119160110083

def get_age(count):
    count -= 1  # 递推重做的事
    if count == 0:  # 结束的条件
        age = 18
        return age
    return get_age(count) + 2  # 回溯放回重复做的事

print(get_age(5))
def get_age(count):
    if count == 1:
        return 18
    return get_age(count - 1) + 2  # 在这一步开始执行函数

print(get_age(5))  # 26
1.3案例2
打印出列表中每一个元素(列表除外)
list1 = [1, [2, [3, [4, [5, [6, [7, [8, [9, [10, [11, [12, [13, [14, ]]]]]]]]]]]]]]
list1 = [1, [2, [3, [4, [5, [6, [7, [8, [9, [10, [11, [12, [13, [14, ]]]]]]]]]]]]]]

def display(list1):
    for i in list1:
        if type(i) is int:
            print(i, end=' ')
        else:
            display(i)

display(list1)
1.4案例3
算法:递归二分法
算法是解决问题的最高效方式。

快速找出某个值时候在列表的位置
二分法能的使用场景:列表必须是有序的,正序号倒序都行。
(当我们要查找的元素就在数据集的开头那么该算法可能不是很高效)

list1 = [11, 23, 43, 57, 68, 76, 81, 99, 123, 321, 432, 567, 666, 712, 899, 999, 1111]
将数据从中间一分为2,判断中间的值,比查找的值大还是小。
在每次的基础上筛选出一半的值。
找到最后,要么存在要么不存在。
list1 = [11, 23, 43, 57, 68, 76, 81, 99, 123, 321, 432, 567, 666, 712, 899, 999, 1111]

# 查找的值
num = 23

# 获取中间的值的索引,整除

def find_num(list1):
    if not list1:
        print('没有这个数据')
        return
    # 获取中间值
    average = len(list1) // 2
    if list1[average] < num:
        # 获取右边的列表
        r_list = list1[average+1:]
        find_num(r_list)
    elif list1[average] > num:
        # 获取右边的列表
        l_list = list1[:average]
        find_num(l_list)
    else:
        print('找到了')

find_num(list1)
list1 = [11, 23, 43, 57, 68, 76, 81, 99, 123, 321, 432, 567, 666, 712, 899, 999, 1111]


def find_num(list1, num):

    if len(list1) == 0:  # 结束条件 列表为空
        print('查找的数字不存在')
        return

    # 定义一个中间值
    middle = len(list1) // 2  # 只能是整除 1//2 = 0

    print(middle, list1[middle], num)
    # 输入的值与中间值做比较
    if num < list1[middle]:  # 比中间值小向 往列表的左←边查找

        list1 = list1[0:middle]
        find_num(list1, num)
    elif list1[middle] < num:  # 比中间值大向 往列表的右→边查找

        list1 = list1[middle + 1:]
        find_num(list1, num)
    else:
        print('找到了')
        return


num = int(input('输入查找的数字>>>:').strip())
find_num(list1, num)

image-20220105234219076

2.三元表达式

2.1格式
当需求为二选一的情况下推荐使用三元表达式。
格式:
条件成立采用的值  if 条件 else 条件不成立采用的值。
值不能是关键字, ... 属于特殊的符号,不算关键字
2.2使用
a = 0
b = 1
print(a if a > b else b)
import sys

def func1():
    print('哈哈哈')
    sys.exit()

while True:
    pass # 程序xxx
    func1() if input('输入q退出否则继续>>>:').strip() == 'q' else ...
2.3嵌套
可以嵌套到时尽量不要去使用。Python语句注重可读性.
a = 0
b = 1
c = 2
print(a if a > b else (c if c > b else a))

3.生成式

快速生成一个容器类型的数据值。
for 与if 使用不能再用 else,应为else 能跟 for也能跟 if 出现矛盾。

元组生成的是迭代器。
3.1列表生成式
print([i for i in range(10)])  # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
list1 = ['kid', 'qz', 'qq']
print([i + '_vip' for i in list1])  # ['kid_vip', 'qz_vip', 'qq_vip']
list1 = ['kid_vip', 'qz_vip', 'qq_vip']
print([i.strip('_vip') for i in list1])  # ['kid', 'qz', 'qq']
list1 = ['kid_vip', 'qz_vip', 'qq_vip']
print([i.strip('_vip') for i in list1 if i == 'kid_vip'])  # ['kid']
3.2字典生成式
list1 = ['name', 'age', 'hobby']
list2 = ['kid', 18, 'red']

dic = {}
for i in range(len(list1)):
    dic[list1[i]] = list2[i]

print(dic)  # {'name': 'kid', 'age': 18, 'hobby': 'red'}
list1 = ['name', 'age', 'hobby']
list2 = ['kid', 18, 'red']


res = {list1[i]: list2[i] for i in range(len(list1))}  # {'name': 'kid', 'age': 18, 'hobby': 'red'}
print(res)
枚举:是列出某些有穷序列集的所有成员的程序。
enumerate(可迭代对象,start=0) 函数 会产生两个结果
第一个是从0开始的数字
第二个是被循环对象里面的元素,默认不写start=0.
   通过start参数控制起始位置
for i in enumerate([1, 2, 3]):
    print(i)
"""
(0, 1)
(1, 2)
(2, 3)
"""
for x, y  in enumerate([1, 2, 3]):
    print(x, y )
"""
0 1
1 2
2 3
"""
list1 = ['name', 'age', 'hobby']

res = {k: v for k, v in enumerate(list1)}  # {0: 'name', 1: 'age', 2: 'hobby'}
print(res)
list1 = ['name', 'age', 'hobby']

res = {'k'+str(k): v for k, v in enumerate(list1)}  # {0: 'name', 1: 'age', 2: 'hobby'}
print(res)
list1 = ['name', 'age', 'hobby']


res = {'k' + str(k): v for k, v in enumerate(list1, start=1)}  # {'k1': 'name', 'k2': 'age', 'k3': 'hobby'}
print(res)
list1 = ['name', 'age', 'hobby']

res = {'k' + str(k): v for k, v in enumerate(list1) if k != 0}
print(res)
3.3集合生成式
list1 = ['name', 'age', 'hobby']

res = { i for i in list1}  # {'hobby', 'age', 'name'}
print(res)

3.4迭代器

元组生成的是一个可迭代对象。
list1 = ['name', 'age', 'hobby']

res = (i for i in list1)  # <generator object <genexpr> at 0x0000028C7233C2B0>
print(res)
下例代码报错的原因
# a.txt
123456789
123456789
123456789
with open('a.txt') as f:
    g1 =(len(line) for line in f)  # 错 ()是可迭代对象

print(sum(g1))

"""
为何报错?ValueError: I/O operation on closed file.
ValueError: 对已关闭文件的 IO 操作。

迭代器只有在使用的时候才执行,
len()函数值走了过场什么都什么做.

你以为代码是:
g1 = (10, 10, 10)
print(len(g1))
其实代码是这样的:
g1 = (len(line),len(line),len(line)
一个line代表一行. 

当需要执行的时候,文件的io操作已经关闭了,所有报错.
"""

image-20220209072834194

with open('a.txt') as f:
    g1 = (len(line) for line in f)  # 错 ()是可迭代对象
    
    # 在没有回收文件句柄的时候代码就可以正常的执行
    print(sum(g1))  
自己编了一个故事:

1.买彩票,买了三个张,然后直接走了.

(前题条件: 只能在彩票店里面的机器去查询自己中奖)

2.在回来的时候.店关门了,自己拿着票没法去查询是否中奖.

3.只有彩票店没关门的时候符合条件,才能去查询.

4.匿名函数

4.1定义
匿名函数一般不会单独使用 都是配合其他函数一起使用。
格式:
lambda 形参:返回值
将形参做处理得到一个结果,将这个结果返回.
4.2调用
print((lambda x: x ** 2)(2))  # 加上括号调用, 括号内传入参数

*版本差异

Python 2  Python 3 中的不同:
 Python 3.x 中为了减少内存,map()、zip() filter()返回的是一个可迭代对象。
如需展示列表,需手动 list() 转换。
Python2 返回列表
Python3 返回生成器

5.map函数

5.1定义
map函数:会根据提供的函数对指定序列做映射。
映射:就是给一个对象(变量)起一个唯一的别名。
格式:
map(function,iterable)  
function 函数名称,通过该函数对后续参数iterable进行处理
iterable 可迭代对象,比如:字符串、列表、字典、元组、集合等

可迭代对象中每个元素依次取出来,交给函数做处理,
被函数进行处理得到一个新的值,不会改变原来的值。
5.2实例
当前阶段,返回生成器使用list转换成一个列表展示下。
# 将 纯数字字符 装换为 数字
list1 = ['0', '1', '2', '3', '4']
res = map(int, list1)
print(list(res))  # [0, 1, 2, 3, 4]
# 将 字符串装换为一个列表
list1 = '12345'
res = map(int, list1)
print(list(res))  # [1, 2, 3, 4, 5]
5.2搭配匿名函数
list1 = [1, 2, 3, 4, 5, 6, 7, 8, 9]

print(list(map(lambda x: x ** 2, list1)))  # [1, 4, 9, 16, 25, 36, 49, 64, 81]
list1 中的每个元素依次作为参数传递给匿名函数,
map的返回值需要list()转为列表才显示值。

6.zip函数

6.1定义
zip函数:用于将可迭代对象最为参数,将对象中对应的元素打包成一个个元组,
然后返回列表套元组的格式数据。
格式:
zip([iterable1, iterable2, ...])
iterable:可迭代对象,可以有多个。
多行可迭代对象中,以元素最短的对象为准打包,因次被称为拉链函数。
6.2实例
list1 = ['k1', 'k2', 'k3', 'k4', 'k5']
list2 = ['v1', 'v2', 'v3', 'v4', 'v5', 'v6']
list3 = ['x1', 'x2', 'x3', 'x4', 'x5', 'x6']

res = zip(list1, list2, list3)
print(list(res))
# [('k1', 'v1', 'x1'), ('k2', 'v2', 'x2'), ('k3', 'v3', 'x3'), ('k4', 'v4', 'x4'), ('k5', 'v5', 'x5')]
6.3转为字典
当两个可迭代对象拉链操作后,可以直接dict() 转为字典.
* 键一定是不可变类型的值才行,也就是说每一组元组索引0是不可变类型的值.
print(dict(zip([1, 2, 3], [4, 5, 6])))
# {1: 4, 2: 5, 3: 6}

# 报错 类型错误:不可哈希的类型:“列表”
print(dict(zip([[1,], 2, 3], [4, 5, 6])))  
list1 = ['k' + str(i) for i in range(1, 6)]  # ['k1', 'k2', 'k3', 'k4', 'k5']
list2 = ['v' + str(i) for i in range(1, 7)]  # ['v1', 'v2', 'v3', 'v4', 'v5', 'v6']

res = zip(list1, list2)
print(list(res))  # [('k1', 'v1'), ('k2', 'v2'), ('k3', 'v3'), ('k4', 'v4'), ('k5', 'v5')]

print(dict([('k1', 'v1'), ('k2', 'v2'), ('k3', 'v3'), ('k4', 'v4'), ('k5', 'v5')]))
# {'k1': 'v1', 'k2': 'v2', 'k3': 'v3', 'k4': 'v4', 'k5': 'v5'}

7.max/min

都是比较数字大小.
字符按ASCII 所对应的10进制逐位比较,只需要比出一个大小就结束比较。
  对应
0-9  48-57
A-Z  65-90
a-z  97-122
6.1定义
max()函数返回给定参数的最大值,参数可以是列表。
min()函数返回给定参数的最小值,参数可以是列表。
格式:
max(数值表达式..., key=None)
min(数值表达式..., key=None)

key是给匿名函数使用的.
6.2实例
list1 = ['k1', 'k2', 'k3', 'k4', 'k5']
list2 = ['v1']


print(max(list1))  # k5   字符按ASCII 所对应的10进制逐位比较,
print(max(list1, list2))  # ['v1']   
6.3搭配匿名函数
# 键比较
dic = {'k1': 3000,
       'k2': 2000,
       'k3': 1000,
       'k4': 600,
       'k5': 700}

print(max(dic))  # k5  默认只能比较键
# 值比较
dic = {'k1': 3000,
       'k2': 2000,
       'k3': 1000,
       'k4': 600,
       'k5': 700}

print(max(dic, key=lambda key: dic[key]))  # k1  自动for循环取值 之后再比较大小
# 值一样大
dic = {'k1': 2000,
       'k2': 3000,
       'k3': 1000,
       'k4': 3000,
       'k5': 700}

print(max(dic, key=lambda key: dic[key]))  # k2

"""
k1 与 k2 比较 k2大保留

k2 与 k1 比较 k2大保留

k2 与 k3 比较 k2不小于k3 k2保留
"""

7.filter

7.1定义
filter()函数用于过滤序列,过滤不符合条件的元素。
返回由 符合条件的元素组成的新列表。
filter(function, iterable)
function 判断函数。
iterable 可迭代对象。
第一个为函数,第二个为序列,序列的每个元素作为参数传递给函数进行判断,
然后返回 True  False,最后将返回 True 的元素放到新列表中。
7.2实例
res = filter(lambda x: x > 3, [1, 2, 3, 4, 5, 6, 7, 8])
print(list(res))  # [4, 5, 6, 7, 8]
res = filter(lambda x: x % 2, range(1, 101))  # x % 2 在这等同与 if x % 2 结果为0就被过滤
print(list(res))  # 奇数

res = filter(lambda x: not x % 2, range(1, 101))  
print(list(res))  # 偶数

8.reduce

8.1定义
seduce()函数会对参数序列中元素进行累积。
先从可迭代对象中取两个参数,在函数中进行进行计算得出一个结果,再从迭代对象中取一个值计算···
Python3.x reduce() 已经被移到 functools 模块里,如果我们要使用,需要引入 functools 模块来调用 reduce()
seduce(function, iterable, initializer)
function     函数,有两个参数
iterable     可迭代对象
initializer  可选,初始参数
8.2实例
from functools import reduce

res = reduce(lambda x, y: x + y, [1, 2, 3, 5, 5])
print(res)  # 16
from functools import reduce

res = reduce(lambda x, y: x + y, [1, 2, 3, 5, 5], 3)  # 基础值
print(res)  # 19

9.练习

1.a.txt文件内容如下,标题为:姓名,性别,年纪,薪资
kid male 18 3000
qq male 19 30000
qaq female 18 20000
qz female 20 10000

要求:
1.从文件中取出每一条记录放入列表中,
列表的每个元素都是{'name':'kid','gender':'male','age':18,'salary':3000}的形式

2. 根据1得到的列表,取出所有人的薪资之和
3. 根据1得到的列表,取出所有的男人的名字
4. 根据1得到的列表,将每个人的信息中的名字映射成首字母大写的形式
5. 根据1得到的列表,过滤掉名字以a开头的人的信息
6. 根据1得到的列表,取出薪资最高的人的信息
7. 根据1得到的列表,取出最年轻的人的信息
8. 根据1得到的列表,给用户名加上_vip的后缀,  kid_vip
9. 求文件a.txt中最长的行的长度(长度按字符个数算,需要使用max函数)
10.求文件a.txt中总共包含的字符个数
with open('a.txt', mode='rt', encoding='utf8') as rf:
    user_info = rf.readlines()

print(user_info)
# ['kid male 18 3000\n', 'qq male 19 30000\n', 'qaq female 18 20000\n', 'qz female 20 10000\n']


# 去除\n 在切分
user_info = [i.strip('\n').split() for i in user_info]
print(user_info)
# [['kid', 'male', '18', '3000'], ['qq', 'male', '19', '30000'],
# ['qaq', 'female', '18', '20000'], ['qz', 'female', '20', '10000']]

# 字典的键
dic_key_list = ['name', 'gender', 'age', 'salary']

# zip
user_info = [ dict(zip(dic_key_list, i)) for i in user_info]
print(user_info)
"""
[
{'name': 'kid', 'gender': 'male', 'age': '18', 'salary': '3000'},
 {'name': 'qq', 'gender': 'male', 'age': '19', 'salary': '30000'}, 
 {'name': 'qaq', 'gender': 'female', 'age': '18', 'salary': '20000'}, 
 {'name': 'qz', 'gender': 'female', 'age': '20', 'salary': '10000'}
]
"""

# 2. 根据1得到的列表,取出所有人的薪资之和
saraly_list = [int(i.get('salary'))  for i in user_info]
print(saraly_list)
# [3000, 30000, 20000, 10000] 不要直接sum 这是练习

from functools import reduce

count = reduce(lambda x, y : x + y, saraly_list)
print(count)  # 63000

# 3.根据1得到的列表,取出所有的男人的名字
male_list = [i.get('name') for i in user_info if i.get('gender') == 'male']
print(male_list)

# 4.根据1得到的列表,将每个人的信息中的名字映射成首字母大写的形式
name_list = [i.get('name').capitalize() for i in user_info]
print(name_list)

# 5.根据1得到的列表,过滤掉名字以q开头的人的信息
filter_list = [i for i in user_info if not i.get('name').startswith('q')]
print(filter_list)

# 6. 根据1得到的列表,取出薪资最高的人的信息
print(max(user_info, key=lambda dic: dic.get('salary')))
# {'name': 'qq', 'gender': 'male', 'age': '19', 'salary': '30000'}
# 把 user_info 一个个元素传进 匿名函数中 匿名函数把salary的值返回去做比较

# 7.根据1得到的列表,取出最年轻的人的信息
print(min(user_info, key=lambda dic: dic.get('age')))  # 两个人年纪一样大的 显示第一个小的
# {'name': 'kid', 'gender': 'male', 'age': '18', 'salary': '3000'}

# 8.根据1得到的列表,给用户名加上_vip的后缀, 如 kid_vip
[dic.update({'name': dic['name'] + '_vip'}) for dic in user_info]
# 直接修改可变类型内的值
print(user_info)
# 9. 求文件a.txt中最长的行的长度(长度按字符个数算,需要使用max函数)
with open('a.txt', mode='rt', encoding='utf8') as rf:
    user_info = rf.readlines()

print(user_info)
# 去除\n , 每一行都有\n 去不去都不所谓
user_info = [i.strip('\n') for i in user_info]

print(user_info)
# ['kid male 18 3000', 'qq male 19 30000', 'qaq female 18 20000', 'qz female 20 10000']
dic = dict(enumerate(user_info, start=1))
print(dic)
# {1: 'kid male 18 3000', 2: 'qq male 19 30000', 3: 'qaq female 18 20000', 4: 'qz female 20 10000'}
line = max(dic, key=lambda key: len(dic[key]))
print(f'第{line}行的字符数最多')  # 3   第三行
# 10.求文件a.txt中总共包含的字符个数
with open('a.txt', mode='rt', encoding='utf8') as rf:
    num = [len(i) for i in rf ]

print(num)
from functools import reduce
count = reduce(lambda x, y : x+y, num, 0)
print(count)
2. 使用递归打印斐波那契数列(前两个数的和得到第三个数,如:1, 2, 3, 5, 8, 13..)
def num(x, y):
    if y > 100:  # 结束条件
        return

    # z = y
    # y = x + y
    # x = z
    
    y, x = y + x, y
    print(y, end=' ')  # 1 2 3 5 8 13 21 34 55 89 144 
    
    num(x, y)
    
num(0, 1)
3. 一个嵌套很多层的列表,如 list1 = [1, 2, [3, [4, 5, 6, [7, 8, [9, 10, [11, 12, 13, [14, 15]]]]]]],用递归取出所有的值
list1 = [1, 2, [3, [4, 5, 6, [7, 8, [9, 10, [11, 12, 13, [14, 15]]]]]]]


def get_num(list1):
    if not len(list1):  # 结束条件
        return

    for i in list1:
        # i是整数就打印
        if type(i) == int:
            print(i, end=' ')
        # 否则就 递归
        else:
            get_num(i)


get_num(list1)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值