模块与包

函数的递归调用

定义:在调用一个函数的过程中直接或又间接调用该函数本身,称之为函数的递归调用。

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)

总结:

  1. 进入下一次时,问题的规模必须降低
  2. 递归调用必须需要一个明确的结束条件
  3. 在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   #访问日志 
posted @ 2017-10-20 23:59  zz小公子  阅读(100)  评论(0编辑  收藏  举报