一、函数递归
1.引入
函数的递归调用:就是在调用一个函数的过程中又直接或间接地调用自己
示例1:直接调用自己
def foo():
print('hello')
foo()
foo() # 死递归,会抛出异常,调用python对象超过最大递归深度
示例2:间接调用自己
def bar():
print('from bar')
foo()
def foo():
print('hello')
bar()
foo() # 也会抛出异常
为何死递归会抛出异常???
应为无限的递归会导致内存溢出,所以python设定了最大的递归层数,我们应该给递归设置结束条件,然后返回
import sys
print(sys.getrecursionlimit()) # 可查看当前最大递归层数
print(sys.setrecursionlimit(2000)) # 可设置新的最高递归层数
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)
二分法使用场景:
nums=[111,[222,[333,[444,[5555,[6666,[777,[888,[9999]]]]]]]]]
def func(l):
for x in l:
if type(x) is list:
# 把自身的代码重新再调用一次
func(x)
else:
print(x)
func(nums)
'''
从小到大排列的一个数字列表,找某个数是否在其中
'''
nums = [11, 13, 32, 47, 53, 73, 84, 91,101,111,222,333,444,5555]
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,85)
3.递归的应用场景:当你不知道该重复做多少次,但是知道在什么情况下该结束的时候,用递归会很好。
二、三元表达式
'''
对于这样一个判断条件,就产生结果的函数,可以用三元表达式简化,省去了构造函数
'''
def max2(x,y):
if x > y:
return x
else:
return y
三元表达式: res = 表达式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[k]
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编写并链接到python解释器的内置模块
2、为何要用模块
使用别人的模块:
1、拿来主义,提升开发效率
自定义模块:
1、他人的功能无法满足所有,有些功能需要自己编写
2、解决代码冗余
3、如何用模块
当前我们有一个spam.py的文件,内容如下:
# spam.py
print('from the spam.py')
__all__ = ['money', 'read1'] # 利用__all__可以限制*号的导入,表示只对*开发其后的功能,若不写,默认全开放
money = 1000
def read1():
print('spam模块:', money)
def read2():
print('spam模块')
read1()
def change():
global money
money = 0
文件名是spam.py,模块名则是spam
'''
导入方法1:
import spam # 导入模块,会运行py文件的代码
方法1导入模块发生的事情
1、触发被导入的模块的运行,产生一个模块的名称空间,把模块中的名字都丢进去
2、会在当前执行文件中得到一个名字spam,该名字是指向被导入模块的名称空间的
方法1使用模块的方法:
'''
import spam
print(money)
print(spam.money)
spam.read1()
spam.read2()
spam.change()
print(spam.money)
print(money)
----------------------------------
from the spam.py
10
1000
spam模块: 1000
spam模块
spam模块: 1000
0
10
'''
导入方法2:
from spam import * #导入模块,运行py文件代码
方法2导入模块发生的事情
1、触发被导入的模块的运行,产生一个模块的名称空间,把模块中的名字都丢进去
2、会在当前执行文件中得到名字
money=模块spam中的money对应值的内存地址
read1=模块spam中的read1对应值的内存地址
read2=模块spam中的read2对应值的内存地址
------------------------------------
from the spam.py
'''
from spam import *
print(money)
money=111
print(money) # 利用from import导入,有时会名称覆盖
--------------------------------------------------------
from the spam.py
1000
111
money=2000
read1()
----------------------------
from the spam.py
spam模块: 1000
'''
之后的导入,名字spam直接引用首次导入产生的名称空间,不会再执行模块的内的代码了
'''
import spam
import spam
-----------------------
无代码运行
一行导入多个模块
import spam,m1,m2,m3 # 不推荐
为导入的模块起别名
import spamasdfasfsadfadfasfd as spam
起别名的好处,小案例
示例:
#mysql.py
def sqlparse():
print('from mysql sqlparse')
#oracle.py
def sqlparse():
print('from oracle sqlparse')
#test.py
db_type=input('>>: ')
if db_type == 'mysql':
import mysql as db
elif db_type == 'oracle':
import oracle as db # 取一样的别名,就使得我们后续的代码不用修改
db.sqlparse()
...很多代码使用db.xxx的代码