1.4 函数的递归调用
函数的递归调用是指在调用一个函数的过程中又直接或者间接的调用到本身,是函数嵌套调用的一种特殊形式。
直接调用气本身
# def f1():
# print('是我是我还是我')
# f1()
# f1()
间接调用本身
def f1():
print('===>f1')
f2()
def f2():
print('===>f2')
f1()
f1()
两种情况下的递归调用都是一个无限循环的过程,但在python对函数的递归调用的深度做了限制,因而并不会像大家所想的那样进入无限循环,会抛出异常,要避免出现这种情况,就必须让递归调用在满足某个特定条件下终止。
#1. 可以使用sys.getrecursionlimit()去查看递归深度,默认值为1000,虽然可以使用
sys.setrecursionlimit()去设定该值,但仍受限于主机操作系统栈大小的限制
#2. python不是一门函数式编程语言,无法对递归进行尾递归优化。
二分法
# 算法:是高效解决问题的办法
# 算法之二分法
# 需求:有一个按照从小到大顺序排列的数字列表
# 需要从该数字列表中找到我们想要的那个一个数字
# 如何做更高效???
nums=[-3,4,7,10,13,21,43,77,89]
find_num=10
nums=[-3,4,13,10,-2,7,89]
nums.sort()
print(nums)
# 方案一:整体遍历效率太低
# for num in nums:
# if num == find_num:
# print('find it')
# break
# 方案二:二分法
# def binary_search(find_num,列表):
# mid_val=找列表中间的值
# if find_num > mid_val:
# # 接下来的查找应该是在列表的右半部分
# 列表=列表切片右半部分
# binary_search(find_num,列表)
# elif find_num < mid_val:
# # 接下来的查找应该是在列表的左半部分
# 列表=列表切片左半部分
# binary_search(find_num,列表)
# else:
# print('find it')
nums=[-3,4,7,10,13,21,43,77,89]
find_num=8
def binary_search(find_num,l):
print(l)
if len(l) == 0:
print('找的值不存在')
return
mid_index=len(l) // 2
if find_num > l[mid_index]:
# 接下来的查找应该是在列表的右半部分
l=l[mid_index+1:]
binary_search(find_num,l)
elif find_num < l[mid_index]:
# 接下来的查找应该是在列表的左半部分
l=l[:mid_index]
binary_search(find_num,l)
else:
print('find it')
binary_search(find_num,nums)
匿名函数与lambda
对比使用def关键字创建的是有名字的函数,使用lambda关键字创建则是没有名字的函数,即匿名函数,语法如下
# 1、定义
lambda x,y,z:x+y+z
#等同于
def func(x,y,z):
return x+y+z
# 2、调用
# 方式一:
res=(lambda x,y,z:x+y+z)(1,2,3)
# 方式二:
func=lambda x,y,z:x+y+z # “匿名”的本质就是要没有名字,所以此处为匿名函数指定名字是没有意义的
res=func(1,2,3)
模块
模块就是一系列功能的集合体,分为三大类
1.1.1 内置的模块
1.1.2 第三方模块
1.1.3 自定义模块
一个python文件本身就是一个模块,文件名m.py,模块名叫m
了解:模块分为四种形式
'''
1、使用python编写的.py文件
2、已被编译为共享库或DLL的c或c++扩展
3、把一系列模块组织到一起的文件夹(注:文件夹下有一个__init__.py文件,该文件夹称之为包)
4、使用c编写并链接到python解释器的内置模块
'''
1.3.1 为什么有模块
内置与第三方的模块拿来就用,无需定义,可以极大的提升自己的开发效率
自定义模块:可以将程序的各部分功能提取出来放到一个模块中为大家共享使用,减少代码冗余,程序组织结构更加清晰
1.3.2 模块的使用
import 模块名
# 1、首次导入模块会发生3件事
# 1、执行foo.py
# 2、产生foo.py的名称空间,将foo.py运行过程中产生的名字都丢到foo的名称空间中
# 3、在当前文件中产生的有一个名字foo,该名字指向2中产生的名称空间
# 之后的导入,都是直接引用首次导入产生的foo.py名称空间,不会重复执行代码(即不会重复导入同一模块)
# 2、引用:
# print(foo.x)
# print(foo.get)
# print(foo.change)
# 强调1:模块名.名字,是指名道姓地问某一个模块要名字对应的值,不会与当前名称空间中的名字发生冲突
# 强调2:无论是查看还是修改操作的都是模块本身,与调用位置无关
# 3、可以以逗号为分隔符在一行导入多个模块(不建议在一行同是导入多个模块)
# 4、导入模块的规范
# I. python内置模块
# II. 第三方模块
# III. 程序员自定义模块
import time
import sys
import 第三方1
import 自定义模块1
# 5、import 。。。 as 。。。
import foo as f # f=foo
f.get()
# 6、模块是第一类对象
# 7、自定义模块的命名应该采用纯小写+下划线的风格
# 8、可以在函数内导入模块
def func():
import foo