递归函数、三元表达式、二分法、列表和字典生成器、匿名函数


一、递归函数

  1、关于递归函数

    递归函数是直接或间接的调用自己

    由此会使函数不间断的调用自己,所以递归一定要有结束条件

    默认的递归深度(循环次数)是1000次

    递归深度的查看和修改方式

import sys  # 引入sys模块

print(sys.getrecursionlimit())  # 查看最大递归深度
# 结果为1000
sys.setrecursionlimit(2000)  # 修改最大递归深度
print(sys.getrecursionlimit())
# 结果为2000

  2、简单案例

count = 1


def index():
    global count
    count += 1
    print('from index', count)
    index()


index()

  3、实际应用

# 有5个人,如果A比B大2岁,B比C大2岁,以此类推,现知E18岁,求A的年纪
# 思路:a=b+2  b=c+2  c=d+2  d=e+2 e=18
# 当age=18的时候,循环4次age=age+2
# 或者定义一个函数,让函数返回值依然为该函数名,完成函数递归,代替循环
def age(n):  # 定义一个函数
    if n == 1:
        return 18  # 设置结束条件

    return age(n - 1) + 2  # 返回值的名字依次减1,值依次加2


print(age(5))  # 打印出n=5时的结果

  4、应用进阶

# 要求把列表内的数值全部拆分出来
l = [1, [2, [3, [4, [5, [6, [7, [8, [9, [10, ]]]]]]]]]]


# 分析:列表是整型+列表额嵌套模式
# 思路:如果是整型,直接打印输出;如果不是整型(也就是列表格式),循环
# 具体方式:定义一个递归函数,如果是整型,直接打印输出
# 如果是列表,递归循环如果
def get_num(l):
    for i in l:
        if type(i) is int:
            print(i)
        else:
            get_num(i)


get_num(l)

二、三元表达式

  1、三元表达式

    res = a if 条件 else b

    res表示:如果满足条件返回a,否则返回b

  2、三元表达式嵌套

    res = a if 条件1 else (‘hello’ if 条件2 else ‘world’)

    res表示:如果满足条件1,返回a,否则执行(‘hello’ if 条件2 else ‘world’);

         ‘hello’ if 条件2 else ‘world’,如果满足条件2,返回‘hello’,否则返回‘world’

    三次嵌套、四次嵌套,都依次类推

  3、实际应用

# 让用户输入判断
cmd = input('username:').strip()
res = '帅哥' if cmd == 'ly' else 'dsb'
print(res)

三、算法之二分法

  算法是解决问题放入高效方法

  常见的算法包括:二分法、冒泡算法、选择排序

  二分法是指,在顺序排列的组合中,高效找到所需值的一种方法。

  具体是不断对比中间的数值,判断所属范围在中间的左边或者右边。

  优点是对末尾数值方便快速查找,缺点是查找第一个数值比不了传统方法(for循环遍历查找)

l = [1, 2, 3, 4, 5, 6, 11, 22, 34, 44, 55, 66, 67, 333, 444]


def my_half(target_num, l):  # 
    # 1. 从列表中取一个中间值
    middle_index = len(l) // 2  # 7

    # 2. 比较
    if target_num > l[middle_index]:
        # 要找的元素在右边
        l_right = l[middle_index + 1:]
        my_half(target_num, l_right)
    elif target_num < l[middle_index]:
        # 要找的元素一定在左边
        l_left = l[:middle_index]
        my_half(target_num, l_left)
    else:
        print('找到了,哈哈哈哈')


my_half(34, l)

四、列表生成式

  1、传统方式:

    列表生成器是列表使用的又一种方法,可以实现简单的列表再生成

    其他方式也可以实现,且更能满足多种条件下应用

    所以一般不使用列表生成式,了解即可

# 现在有一个列表,要求给列表中的每个元素添加‘_dl’
l = ['ly', 'jason', 'tom']

new_list = []  # 定义一个空列表,用于改变后的新内容
for i in l:
    new_list.append(i + '_dl')  # 给l的每一个元素添加‘_dl’
print(new_list)

  2、列表生成式

  
    for循环条件下的列表生成式
    res = [i + '_dsb' for i in l]
# 现在有一个列表,要求给列表中的每个元素添加‘_dl’
l = ['ly', 'jason', 'tom']

new_list = []  # 定义一个空列表,用于改变后的新内容

res = [i + '_dsb' for i in l]
print(res)

    if...else条件下的列表生成式

    res = [i + '_dsb' if i != 'jason' else i for i in l]
# 现在有一个列表,要求给列表中的每个元素添加‘_dl’,除了jason
l = ['ly', 'jason', 'tom']

new_list = []  # 定义一个空列表,用于改变后的新内容

res = [i + '_dsb' if i != 'jason' else i for i in l]
print(res)

五、字典生成式

  1、传统方式:

# l1中的元素作为字典的k,l2中的元素作为字典的v
l1 = ['name', 'age', 'hobby']
l2 = ['ly', 18, 'music']

# 定义一个空字典
new_dict = {}
for i in range(len(l1)):  # 以l1的长度作为循环的范围,也就是0,1,2,3
    new_dict[l1[i]] = l2[i]

print(new_dict)

  2、字典生成式

    补充知识点:enumerate枚举

# l1中的元素作为字典的k,l2中的元素作为字典的v
l1 = ['name', 'age', 'hobby']
l2 = ['ly', 18, 'music']


# 补充:enumerate枚举

# 定义一个空字典
new_dict = {}
res = {l1[i]: l2[i] for i, j in enumerate(l1)}
print(res)  # 结果为{'name': 'ly', 'age': 18, 'hobby': 'music'}

六、匿名函数

  1.定义

    指没有名字的函数

  2、格式

    lambda 参数:返回值

  3、实例对比

    1、非匿名函数得出一个数的平方

# 传统方式
# 这是一个得出平方的有参函数
def index(x):
    return x ** 2


print(index(3))
# 得出结果9

    2、匿名函数得出一个数的平方

      注意:匿名函数一般不单独使用,匿名函数跟内置函数结合使用才是常规做法

# 匿名函数
lambda x: x ** 2
# x是参数:x**2是返回值
print(lambda x: x ** 2)
# 返回 at 0x00000240273FBD08>
print((lambda x: x ** 2)(3))  # 写入实参,可以得到返回值
# 返回9,注意lambda x: x ** 2 和 实参3 都必须用括号括起来

  4、结合内置函数map使用

七、常见的内置函数

  1、map 映射

    1、语法结构

      map(func, *iterables)
      func是函数名,*iterables是可迭代对象

    2、底层原理

      foe循环

    3、实例

# 要求:给列表l中的每一个元素平方,得到一个新列表
l = [1, 2, 3, 4, 5]
# map映射
map(lambda x: x ** 2, l)
# map语法结构map(函数名,可迭代对象)
# lambda语法结构 lambda(参数,返回值)
# lambda与map的结合使用

res = list(map(lambda x: x ** 2, l))
# map()得出的是内存地址,list(map())才是结果
print(res)

# 返回结果[1, 4, 9, 16, 25]

  2、zip 拉链

    实现两个或连个以上列表对应索引位置的一一结合

    (1)传统实现方式

l1 = [1, 2, 3, 4, 5, 6]
l2 = ['ly', 'jason', 'tom', 'kevin', 'tony', 'Pony']
# 先定义一个新变量列表,用于存储结果
list_1 = []
for i in range(len(l1)):  # len(l1)==6,range(6)结果是[0,1,2,3,4,5],顾头不顾尾
    list_1.append((l1[i], l2[i]))  # 注意.append()内只能有一个参数,所以必须把两个括起来
print(list_1)
# 返回结果[(1, 'ly'), (2, 'jason'), (3, 'tom'), (4, 'kevin'), (5, 'tony'), (6, 'Pony')]

    (2)zip实现方式

l1 = [1, 2, 3, 4, 5, 6]
l2 = ['ly', 'jason', 'tom', 'kevin', 'tony', 'Pony']

zip(l1, l2)
res = list(zip(l1, l2))
print(res)
# 返回结果[(1, 'ly'), (2, 'jason'), (3, 'tom'), (4, 'kevin'), (5, 'tony'), (6, 'Pony')]

    (3)zip实现两个以上列表的对应

      注意:如果列表长度不同,以最短的一个输出

l1 = [1, 2, 3, 4, 5, 6]
l2 = ['ly', 'jason', 'tom', 'kevin', 'tony', 'Pony']
l3 = ['a', 'v', 'b', 'c', 'd']
l4 = [111, 222, 333, 444]

zip(l1, l2, l3, l4)
res = list(zip(l1, l2, l3, l4))
print(res)
# 返回结果[(1, 'ly', 'a', 111), (2, 'jason', 'v', 222), (3, 'tom', 'b', 333), (4, 'kevin', 'c', 444)]

  3、max和min

    (1)传统实现方式

l = [1, 2, 3, 4, 66, 77, 8, 99, ]
l.sort()  # 升序
# l.sort(reverse=True)  # 降序
print(l[-1])  # 通过索引-1求最大值
print(l[len(l) - 1])  # 通过len列表长度-1取最大值
# 结果都是99

    (2)max和min实现方式

# 列表
l = [1, 2, 3, 4, 66, 77, 8, 99, ] l4 = [111,222,333] print(max(l)) # 结果是99 print(min(l)) # 结果都是1 print(max(l,l4)) # 结果都是[111, 222, 333] print(min(l,l4)) # 结果都是[1, 2, 3, 4, 66, 77, 8, 99] # 注意:两个列表比较比的是列表的第一个索引值,如果相同继续比较下一位
# 字典
d = {
    'ly': 9999999,
    'jason': 1000,
    'kevin': 2000,
    'tom': 20
}

'''
    字典暴露的是k值,
    按照ASCII码对应的十进制比较
    0:48   
    A:65
    a:97
'''

# max(d, key=None)  # 底层也是for循环
# 其中d是可迭代对象,key是比较的值,没写默认为None
# max函数返回什么值就按照什么值进行比较,所以字典的返回结果还是字段的k
print(max(d, key=lambda key: d[key]))  # 底层也是for循环
# 返回值为ly
print(min(d, key=lambda key: d[key]))  # 底层也是for循环
# 返回值为tom

  4、filter 过滤

# 要求取出列表l中大于30的元素
l = [1, 2, 3, 4, 66, 77, 8, 99, ]

print(list(filter(lambda x: x > 30, l, )))
# 返回值为[66, 77, 99]