一、函数递归调用
1、函数的递归调用:就是在调用一个函数的过程中又直接或间接地调用自己
ps:嵌套调用自己
示例1:直接调用自己
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.setrecursionlimit(2000))#设置最大递归层数
所以:不应该无限递归调用下去,应该在满足某种条件下结束递归调用,然后返回
2、递归调用应该分为两个阶段
(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)
#案例:取出列表中每个值
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)
二、三元表达式
基本语法:表达式1 if 条件 else 表达式2
#原始写法 def max(x,y): if x > y: return x else: return y max(1,2) #利用三元表达式:更加简洁方便 x=111 y=222 res=x if x > y else y print(res)
三元表达式:让代码变得清晰简洁
三、匿名函数
匿名函数即没有名字的函数
基本语法:返回值=(lambda 形参,形参... : 返回值)(传实参,传实参...)
res =(lambda x,y:x+y)(1,2)
#利用匿名函数 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] #用max求最高薪资的人 print(max(salaries, key=lambda k:salaries[k])) #用min求最低薪资的人 print(min(salaries, key=lambda k:salaries[k])) #用sorted按从小到大排序,默认reverse=False,也可以不写,默认sorted就是按照从小到大排序的 print(sorted(salaries,key=lambda k:salaries[k],reverse=False))
#用sorted按从大到小排序,默认reverse=False,利用reverse=True翻转 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、如何用模块
#建文件run1.py ,run2.py , spam.py 利用run1.py run2.py调用spam.py的功能
#文件run.py 利用import spam
ps:文件名有.py 模块名是去掉.py
# 文件名是spam.py,模块名则是spam x=111 import spam # 首次导入模块发生的事情 # 1、触发被导入的模块的运行,产生一个模块的名称空间,把模块中的名字都丢进去 # 2、会在当前执行文件中得到一个名字spam,该名字是指向被导入模块的名称空间的 # 之后的导入,名字spam直接引用首次导入产生的名称空间,不会再执行模块的内的代码了 # import spam # import spam # import spam money = 2000 # print(money) # print(spam.money) # spam.read1() # def read1(): # print('run1.py----read1') # spam.read2() # spam.change() # print(spam.money) # print(money) # 一行导入多个模块 import spam,m1,m2,m3 # 名字之间用,分隔开 不推荐 # 为导入的模块起别名 # import spamasdfasfsadfadfasfd as sm # sm.xxx # 示例: # #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()
#文件run2.py 利用 import spam import spam里的具体功能
# 文件名是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 *#导入spam文件的所有功能,但是如果在spam文件开头有__all__[用列表或元组,这里面写的是名字]的话,只能调用指定范围内的功能;这样在另外一个文件中用from spam import *就这能导入列表/元组中开放的两个名字
from spam import * # print(money) # print(read1) # print(read2) print(change)
#文件spam
# 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
ps:只要一导入一个文件,那么被导入的那个文件就会运行,只要一运行一个文件,就会造一个全局名称空间,把运行过程中产生的名字都丢进去。
小结:
#1 import spam spam.xxx 不会跟当前名称空间里的冲突 每次用名字都要加前缀spam. #1 from spam import xxx xxx 容易跟当前名称空间的冲突,名字容易被覆盖,容易搞混 尽量不要循环导入