模块与包
函数的递归调用
定义:在调用一个函数的过程中直接或又间接调用该函数本身,称之为函数的递归调用。
def func1():
print("from func1")
func1()
func1()
在python中对这种递归调用做了限制,默认是1000次。
当然我们可以修正但实际情况并没有意义。
import sys
#print(sys.getrecursionlimit()) #调用多少次
sys.setrecursionlimit(2000) #更改递归次数
n = 1
def func1()
global n
print("from func1",n)
n += 1
func1()
func1()
递归分为两个重要的阶段
- 递推
- 回溯
这里我理解为在递推到一定的层级,然后回溯一个值结束
n = 1
def age(n):
if n == 1:
return 18
return age(n - 1) + 2
age(5)
总结:
- 进入下一次时,问题的规模必须降低
- 递归调用必须需要一个明确的结束条件
- 在python中没有尾递归优化,递归调用的效率是不高(伪递归优化:在函数的最后一部调用的时候执行return.
#取出所有值
l = [1,2,[3,4,[5,6,[7,8[9]]]]]
def get(l):
for item in l:
if isinstance(item,list): #判断item是不是列表
get(item)
else:
print(item)
get(l)
二分法
前提数字从小到大排列数字列表;从中间分开,计较中间的值,小的话向左找,找到中间后判断知道找到为主。向右同理。
l = [1,2,3,4,5,6,7,8,9,11,12,13,14,15,16,17]
def get(num,l):
if len(l) > 0
mid = len(l) // 2
if > 1[mid]:
l = l[mid+1:]
elif num < l[mid]:
l = l[:mid]
else:
print("find it")
return
get(num,l)
else: print("not find")
get(11,l)
实现类似于.index(30)的效果
l=[1,2,10,30,33,99,101,200,301,402]
def search(num,l,start=0,stop=len(l)-1):
if start <= stop:
mid=start+(stop-start)//2
print('start:[%s] stop:[%s] mid:[%s] mid_val:[%s]' %(start,stop,mid,l[mid]))
if num > l[mid]:
start=mid+1
elif num < l[mid]:
stop=mid-1
else:
print('find it',mid)
return
search(num,l,start,stop)
else: #如果stop > start则意味着列表实际上已经全部切完,即切为空
print('not exists')
return
search(301,l)
#实现类似于l.index(30)的效果
匿名函数
定义:不用定义直接用
lambda n: n**2
#lambda 表示定义匿名函数;
#第一个n为参数
#冒号后面是函数体(匿名函数自带return,不用写,写会报错)
#
#例如:
func = lambda x,y,z=1: x+y+z
func(1,2,3)
#但是这样就没有任何意义了
有名函数和匿名函数的对比
有名函数:循环使用,保存了函数名,通过名字就可以重复使用函数功能
匿名函数:一次性使用,使用后直接被回收
应用场景:匿名函数既没有绑定名字的函数,,没有绑定名字,意味着只能用一次就被回收;所以说匿名函数的应用场景:某一个功能只用一次就结束了
再 max,min,sorted,map,reduce,filter这些内置函数使用的比较多
内置函数
内置函数比较具体
了解内容
#字符串可以提供的参数 's' None
>>> format('some string','s')
'some string'
>>> format('some string')
'some string'
#整形数值可以提供的参数有 'b' 'c' 'd' 'o' 'x' 'X' 'n' None
>>> format(3,'b') #转换成二进制
'11'
>>> format(97,'c') #转换unicode成字符
'a'
>>> format(11,'d') #转换成10进制
'11'
>>> format(11,'o') #转换成8进制
'13'
>>> format(11,'x') #转换成16进制 小写字母表示
'b'
>>> format(11,'X') #转换成16进制 大写字母表示
'B'
>>> format(11,'n') #和d一样
'11'
>>> format(11) #默认和d一样
'11'
#浮点数可以提供的参数有 'e' 'E' 'f' 'F' 'g' 'G' 'n' '%' None
>>> format(314159267,'e') #科学计数法,默认保留6位小数
'3.141593e+08'
>>> format(314159267,'0.2e') #科学计数法,指定保留2位小数
'3.14e+08'
>>> format(314159267,'0.2E') #科学计数法,指定保留2位小数,采用大写E表示
'3.14E+08'
>>> format(314159267,'f') #小数点计数法,默认保留6位小数
'314159267.000000'
>>> format(3.14159267000,'f') #小数点计数法,默认保留6位小数
'3.141593'
>>> format(3.14159267000,'0.8f') #小数点计数法,指定保留8位小数
'3.14159267'
>>> format(3.14159267000,'0.10f') #小数点计数法,指定保留10位小数
'3.1415926700'
>>> format(3.14e+1000000,'F') #小数点计数法,无穷大转换成大小字母
'INF'
#g的格式化比较特殊,假设p为格式中指定的保留小数位数,先尝试采用科学计数法格式化,得到幂指数exp,如果-4<=exp<p,则采用小数计数法,并保留p-1-exp位小数,否则按小数计数法计数,并按p-1保留小数位数
>>> format(0.00003141566,'.1g') #p=1,exp=-5 ==》 -4<=exp<p不成立,按科学计数法计数,保留0位小数点
'3e-05'
>>> format(0.00003141566,'.2g') #p=1,exp=-5 ==》 -4<=exp<p不成立,按科学计数法计数,保留1位小数点
'3.1e-05'
>>> format(0.00003141566,'.3g') #p=1,exp=-5 ==》 -4<=exp<p不成立,按科学计数法计数,保留2位小数点
'3.14e-05'
>>> format(0.00003141566,'.3G') #p=1,exp=-5 ==》 -4<=exp<p不成立,按科学计数法计数,保留0位小数点,E使用大写
'3.14E-05'
>>> format(3.1415926777,'.1g') #p=1,exp=0 ==》 -4<=exp<p成立,按小数计数法计数,保留0位小数点
'3'
>>> format(3.1415926777,'.2g') #p=1,exp=0 ==》 -4<=exp<p成立,按小数计数法计数,保留1位小数点
'3.1'
>>> format(3.1415926777,'.3g') #p=1,exp=0 ==》 -4<=exp<p成立,按小数计数法计数,保留2位小数点
'3.14'
>>> format(0.00003141566,'.1n') #和g相同
'3e-05'
>>> format(0.00003141566,'.3n') #和g相同
'3.14e-05'
>>> format(0.00003141566) #和g相同
'3.141566e-05'
format(了解即可)
compile(str,filename,kind)
filename:用于追踪str来自于哪个文件,如果不想追踪就可以不定义
kind可以是:single代表一条语句,exec代表一组语句,eval代表一个表达式
s='for i in range(10):print(i)'
code=compile(s,'','exec')
exec(code)
s='1+2+3'
code=compile(s,'','eval')
eval(code)
complie(了解即可)
接下来这里是重点
这里将介绍与匿名函数的结合用法和eval和exec
字典的运算:最小值,最大值,排序
salaries={
'egon':3000,
'alex':100000000,
'wupeiqi':10000,
'yuanhao':2000
}
迭代字典,取得是key,因而比较的是key的最大和最小值
>>> max(salaries)
'yuanhao'
>>> min(salaries)
'alex'
可以取values,来比较
>>> max(salaries.values())
>>> min(salaries.values())
但通常我们都是想取出,工资最高的那个人名,即比较的是salaries的值,得到的是键
>>> max(salaries,key=lambda k:salary[k])
'alex'
>>> min(salaries,key=lambda k:salary[k])
'yuanhao'
也可以通过zip的方式实现
salaries_and_names=zip(salaries.values(),salaries.keys())
先比较值,值相同则比较键
>>> max(salaries_and_names)
(100000000, 'alex')
salaries_and_names是迭代器,因而只能访问一次
>>> min(salaries_and_names)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: min() arg is an empty sequence
sorted(iterable,key=None,reverse=False)
!!!lambda与内置函数结合使用!!!
#1、语法
# eval(str,[,globasl[,locals]])
# exec(str,[,globasl[,locals]])
#2、区别
#示例一:
s='1+2+3'
print(eval(s)) #eval用来执行表达式,并返回表达式执行的结果
print(exec(s)) #exec用来执行语句,不会返回任何值
'''
None
'''
#示例二:
print(eval('1+2+x',{'x':3},{'x':30})) #返回33
print(exec('1+2+x',{'x':3},{'x':30})) #返回None
# print(eval('for i in range(10):print(i)')) #语法错误,eval不能执行表达式
print(exec('for i in range(10):print(i)'))
eval与exec
1、文件内容如下,标题为:姓名,性别,年纪,薪资
egon male 18 3000
alex male 38 30000
wupeiqi female 28 20000
yuanhao female 28 10000
要求:
从文件中取出每一条记录放入列表中,
列表的每个元素都是{'name':'egon','sex':'male','age':18,'salary':3000}的形式
2 根据1得到的列表,取出薪资最高的人的信息
3 根据1得到的列表,取出最年轻的人的信息
4 根据1得到的列表,将每个人的信息中的名字映射成首字母大写的形式
5 根据1得到的列表,过滤掉名字以a开头的人的信息
6 使用递归打印斐波那契数列(前两个数的和得到第三个数,如:0 1 1 2 3 4 7...)
7 一个嵌套很多层的列表,如l=[1,2,[3,[4,5,6,[7,8,[9,10,[11,12,13,[14,15]]]]]]],用递归取出所有的值
#1
with open('db.txt') as f:
items=(line.split() for line in f)
info=[{'name':name,'sex':sex,'age':age,'salary':salary} \
for name,sex,age,salary in items]
print(info)
#2
print(max(info,key=lambda dic:dic['salary']))
#3
print(min(info,key=lambda dic:dic['age']))
# 4
info_new=map(lambda item:{'name':item['name'].capitalize(),
'sex':item['sex'],
'age':item['age'],
'salary':item['salary']},info)
print(list(info_new))
#5
g=filter(lambda item:item['name'].startswith('a'),info)
print(list(g))
#6
#非递归
def fib(n):
a,b=0,1
while a < n:
print(a,end=' ')
a,b=b,a+b
print()
fib(10)
#递归
def fib(a,b,stop):
if a > stop:
return
print(a,end=' ')
fib(b,a+b,stop)
fib(0,1,10)
#7
l=[1,2,[3,[4,5,6,[7,8,[9,10,[11,12,13,[14,15]]]]]]]
def get(seq):
for item in seq:
if type(item) is list:
get(item)
else:
print(item)
get(l)
模块
import os,sys
#这就是我们所说的导入模块,那么导入模块到底发生了什么呢
import加载的模块分为四个类别:
- python的.py文件
- 已经被编译好的共享库或DLL的c或C++扩展
- 把一系列模块组织到一起的文件夹(注:文件夹下有一个__init__.py文件,该文件夹称之为包)
- 使用C编写并链接到python解释器的内置模块
在python中,为了提升我们的开发效率,我们会把不同功能的代码放到不同目录下,这样方便维护。我们一般会把代码放到python的环境变量。可以为压缩文件或者文件夹的形式。
&emsp:import都做了些事
- 为源文件(spam模块)创建新的名称空间,在spam中定义的函数和方法若是使用到了global时访问的就是这个名称空间。
- 在新创建的命名空间中执行模块中包含的代码,见初始导入import spam
- 创建名字(导入的模块名字也可以认为是文件)来引用该命名空间
在导入模块的时候都会生成一个名称空间;并且每个名称空间都是独立的;定义在这个模块中的函数,把这个模块的名称空间当做全局名称空间,这样我们在编写自己的模块时,就不用担心我们定义在自己模块中全局变量会在被导入时,与使用者的全局变量冲突;
from……import……
使用from...import...则是将spam中的名字直接导入到当前的名称空间中,所以在当前名称空间中,直接使用名字就可以了、无需加前缀;
from...import...的方式有好处也有坏处
- 好处:使用起来方便了
- 坏处:容易与当前执行文件中的名字冲突
支持别名
例如:
from spam import read as re
多行导入
from spam import (read1,
read2,
read3,
read4)
这里绝对不建议使用from spam import *
软件开发规范
例如:
soft
|--bin
|--start.py #入口文件
|--conf
|--settings.py #配置文件
|--core
|--core.py #主逻辑程序
|--db
|--mysql.py #MySQL数据库
|--lib
|--read_ini.py #调用的库文件
|--log
|--access.log #访问日志