Python学习16——函数递归调用、匿名函数、模块

文章目录

  • 函数递归调用
  • 匿名函数
  • 模块

函数递归调用

一、引用

函数的递归调用:就是在调用一个函数的过程中又直接或者间接的调用自己
示例:直接的调用自己

def foo():
    print('hello')
    foo()
foo()

示例2:间接调用自己

def bar():
    print('from bar')
    foo()
def foo():
    print('hello')
    bar()

foo()

为何死循环递归会出现异常????????
应为无限的递归会导致内存溢出,所以python设定了最大的递归层数

import sys
print(sys.getrecursionlimit())
print(sys.getrecursionlimit(2000))

所以:不应该无限递归调用下去,应该在满足某种条件下结束递归调用,然后返回

二、递归调用应该分为两个阶段

1、回溯(挖井) :一层一层的递归调用下去
2、递推(从井里跳出来):在满足某一条件的情况下结束回溯,然后开始向上一层一层返回

salary(5) = salary(4) + 10
salary(4) = salary(3) + 10
salary(3) = salary(2) + 10
salary(2) = salary(1) + 10
salary(1) = 18

n = 1   salary(n) = 18
n != 1  salary(n) = salary(n-1) + 10

def salary(n):
    if n == 1:
        return 18
    return salary(n-1) + 10
res = salary(5)
print(res)

小案例1:

nums = [111, [222, [333, [444, [555, [666, [777]]]]]]]

def func(l):
    for x in l:
        if type(x) is list:
            # 把自身代码重新调用
            func(x)
        else:
            print(x)
func(nums)

小案例2:从小到大排列的一个数字列表,找数字

nums = [11, 13, 32, 47, 53, 73, 84, 91]


def binary_search(l, find_num):
    print(l)
    if len(l) == 0:
        print('find_num not exists')
        return
    mid_index = len(l) // 2
    if find_num > l[mid_index]:
        right_l = l[mid_index+1:]
        binary_search(right_l, find_num)
    elif find_num < l[mid_index]:
        left_l = l[:mid_index]
        binary_search(left_l, find_num)
    else:
        print('find it')


binary_search(nums, 15)

三元表达式: 表达式1 if 条件 else 表达式2

x = 111
y = 222

res = x if x > y else y
print(res)

匿名函数

匿名函数就是没有名字的函数

res = (lambda x,y:x+y)(1, 2)
print(res)

f = lambda x, y:x + y
print(f)
f(1,2)

特点:没有名字意味着只能用一次,用完之后就是垃圾,所以匿名函数只能用于临时使用一次的场景

salaries = {
    'egon': 4.4,
    'lqz': 3.3,
    'yj': 2.2
}


def func(k):
    return salaries


print(max(salaries, key=lambda k: salaries[k]))
print(min(salaries, key=lambda k: salaries[k]))


print(sorted(salaries, key=lambda k: salaries[k], reverse=True))

模块

1、什么是模块

模块就是一个功能的集合体,不是用来直接运行的,而是用来被导入使用的

模块分为三大来源:
    (1)内置的模块
    (2)第三方模块
    (3)自定义模块
模块分为四种类别:
    (1)一个py文件就是一个模块
    (2)一个文件夹也是一个模块=》包
    (3)已被编译为共享库或DLL的C或C++拓展
    (4)使用C编写并链接到ptython中

2、为何要用模块

使用别人的模块:
    拿来主义,提升开放效率
使用自定义模块:
    (1)别人的代码不够用了,需要自己编写
    (2)解决代码冗余

3、如何用模块
建一个spam.py文件

print('from the spam.py')

_all_ = ['money', 'read1']  #对*加以限制
money = 1000


def read1():
    print('spam模块:', money)


def read2():
    print('spam模块')
    read1()


def change():
    global money
    money = 0

导入模块
例子一:
文件名是spam.py,模块名则是spam

首次导入模块发生的事情
1、触发被导入的模块的运行,产生一个模块的名称空间,把模块中的名字都丢进去
2、会在当前执行文件中得到一个名字spam,该名字是指向被导入模块的名称空间的
之后的导入,名字spam直接引用首次导入产生的名称空间,不会再执行模块的内的代码了

import spam
 import spam
 import spamx=111

import spam


money = 2000

print(money)
print(spam.money)

def read1():
    print('run.py-----read1')

spam.read2()
spam.change()
print(spam.money)
print(money)

一行导入多个模块

import spam,m1,m2,m3    # 不推荐

为导入的模块起别名

import dsfrefdgegdgregfdgwegsdfwe as sm
sm.xxx

例子二:
文件名是spam.py,模块名则是spam

x=111
# from spam import money,read1,read2  # money=spam.money,read1=spam.read1,read2=spam.read2

首次导入模块发生的事情
1、触发被导入的模块的运行,产生一个模块的名称空间,把模块中的名字都丢进去
2、会在当前执行文件中得到名字
money=模块spam中的money对应值的内存地址
read1=模块spam中的read1对应值的内存地址
read2=模块spam中的read2对应值的内存地址

from spam import money,read1,read2
from spam import money,read1,read2
from spam import money,read1,read2
from spam import money,read1,read2

print(money)
print(read1)
print(read2)


money=111
print(money)

money=2000
read1()

def read1():
    print('run.py read1')
read2()

一行导入多个名字

from spam import money,read1

为导入的模块起别名

from spam import money as m

print(m)

from spam import *
from spam import *
print(money)
print(read1)
print(read2)
print(change)