python 第五弹
博客05
python 继续走坑五
函数
python的递归调用
递归调用: 就是函数在无限的调用自身,但是这个也是有限制的.
在前面我们了解到,函数可以当做一个参数,可以在内部调用别的函数,现在我们在自己的函数里来调用自己
def foo(n):
print(n)
if int(n/2) ==0:
return n
return foo(int(n/2))
calc(10)
递归特性:
1. 必须有一个明确的结束条件
2. 每次进入更深一层递归时,问题规模相比上次递归都应有所减少
3. 递归效率不高,递归层次过多会导致栈溢出(在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当
进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用
的次数过多,会导致栈溢出)
查看可以允许递归的次数(默认是1000)
import sys
print(sys.getrecursionlimit())
当然可以修改了,但是这也增加了程序的危险性
print(sys.setrecursionlimit(1000000))
例子: 最常见的就是二分法的应用了,查找一个数字在不在这个序列里,这个序列是按照从小到大的顺序排列
l = [1, 2, 10,33,53,71,73,75,77,85,101,201,202,999,11111]
def search(seq,find_num):
if len(seq) == 0:
print('Not esxit!!!')
return
mid_index = len(seq)//2
mid_num = seq[mid_index]
if find_num > mid_num:
#说明在序列的右边
seq=seq[mid_num+1:]
search(seq,find_num)
elif find_num < mid_num:
#说明在序列的左边
seq=[:mid_num]
search(seq,find_num)
else:
print('Find It')
search(l,33)
yield 函数的另一种用法
先了解一下生成器
-
Generators
Generators are iterators, but you can only iterate over them once. It’s because they do not store all the values in memory, they generate the values on the fly:>>> mygenerator = (x*x for x in range(3)) >>> for i in mygenerator: ... print(i) 0 1 4 -
It is just the same except you used () instead of []. BUT, you cannot perform for i in mygenerator a second time since generators can only be used once: they calculate 0, then forget about it and calculate 1, and end calculating 4, one by one.
yield就像return,接受函数的传递,并返回一个生成器 >>> def createGenerator(): ... mylist = range(3) ... for i in mylist: ... yield i*i ... >>> mygenerator = createGenerator() # create a generator >>> print(mygenerator) # mygenerator is an object! <generator object createGenerator at 0xb7555c34> >>> for i in mygenerator: ... print(i) 0 1 4 这个函数在调用的时候,你写里面的代码不会运行,这个函数返回一个生成器. 当for 在调用这个函数产生的生成器的时候,他会运行你函数代码里面的的内容,当遇到yield的时候,他会返回第一个循环里面产生 的值 -
yield
yield的语句形式: yield 1 yield的表达式形式: x=yield return只能返回一个值,yiled能返回多次值 #yiled能把一个函数变成一个生成器 #yiled能保存当前程序的运行状态 #yiled能作为一个语句形式存在 yield n #yiled能作为一个表达式形式存在 n=yield 可以用send()赋值给n #携程函数 def eater(name): print(name) while True: food=yield #因为碰到yield就停止,所以上面加了while True print ('you eat %s' %food) g=eater('liukang')![]()
g.next()
g.send(‘菜’)
##必须先初始化一下,否会报错”TypeError: can’t send non-None value to a just-started generator”
报错如上图但是我们可以用装饰器来解决这个问题 def init_send(func): def wrapper(*args,**kwargs): res=func(*args,**kwargs) res.__next() return res return wrapper @init_send def eater(name): print(name) while True: food=yield #因为碰到yield就停止,所以上面加了while True print ('you eat %s' %food) g=eater('liukang') g.send('菜') ##这里我没有进行初始化,因为装饰器解决了 或者使用g.netx('菜') food=yield g.send('菜'),先把'菜'传给yield,由yield赋值给food 然后再往下执行,直到再次碰到yield,然后把yield后的返回值返回 -
写个点菜的小程序:
#这个地放是初试化的, def init(func): def wrapper(*args,**kwargs): res=func(*args,**kwargs) res.__next__() return res return wrapper #开始点菜 @init def cai_menu(*args,**kwargs): food_list=[] while True: food=yield food_list.append(food) print('你选择了%s ' % food_list) name=cai_menu() name.send(('脑袋','大腿')) #send 必须用元组的方式来传值
匿名函数
Lambda 函数也叫匿名函数,匿名就是没有名字,在我看来,如果你的函数只是临时一用,而且业务简单的话,就没必要
去创建一个有名字的函数.
- 一个小栗子:
>>> lambda x,y:x+y <function <lambda> at 0x0000022D22563E18> 前面的x,y是数值,冒号后面是返回值,明显在求和.但是没有名字如何使用呢,我们就给他绑定一个名字, 这样就可以了 >>> add = lambda x,y:x+y >>> add(2,3) 5
map,filter,reduce
上面说到了匿名函数,肯定少不了他们几个,算上lambda一共四个内置函数
-
map() 他可以接受两个参数,一个是函数,一个是序列
例子:
map(func,seq)
>>> li=[1,2,3,4,5,]
>>> add = map(lambda x,y:x+y,li)
>>> print(add)
map 会吧列表里的元素逐个循环,放到前面的函数中去.执行函数,返回一个内存地址.使用list()来得到值 -
filter 提供了一个优雅的方式来过滤函数,满足函数的要求才过滤出来
filter(function, sequence):对sequence中的item依次执行function(item),将执行结果为True的item组成一个List/String/Tuple(取决于sequence的类型)
filter(func,seq)li= [1,2,3,4,5] fil = filter(lambda x:x%2,li) >>> print(list(filter)) [1, 3, 5] -
reduce
If seq = [ s1, s2, s3, … , sn ], calling reduce(func, seq) works like this:
At first the first two elements of seq will be applied to func, i.e. func(s1,s2) The list on which reduce() works looks now like this: [ func(s1, s2), s3, … , sn ]
In the next step func will be applied on the previous result and the third element of the list, i.e. func(func(s1, s2),s3)
The list looks like this now: [ func(func(s1, s2),s3), … , sn ]
Continue like this until just one element is left and return this element as the result of reduce()
总的来说就是一个列表[s1,s2,s3,…sn].reduce函数会先把s1与s2拿出来进行计算,然后计算的结果在与s3进行.
以此类推例子: li= [1,2,3,4,5] >>> from functools import reduce >>> add = reduce (lambda x,y:x+y,li) >>> print(add) 15 >>> 在上面的例子中,我导入了一个包,在3里面reduce给封装到这个函数里面了.
谈谈面向过程
在linux中我们经常用grep -rl 关键字 目录 来搜寻东西.现在我们用python来实现
import os
def init(func):
def wrapper(*args,**kwargs):
res=func(*args,**kwargs)
next(res)
return res
return wrapper
@init
def search(target):
while True:
search_path=yield
g=os.walk(search_path)
for par_dir,_,files in g:
for file in files:
file_abs_path=r'%s\%s' %(par_dir,file)
# print(file_abs_path)
target.send(file_abs_path)
@init
def opener(target):
while True:
file_abs_path=yield
# print('opener func==>',file_abs_path)
with open(file_abs_path,encoding='utf-8') as f:
target.send((file_abs_path,f))
@init
def cat(target):
while True:
file_abs_path,f=yield #(file_abs_path,f)
for line in f:
tag=target.send((file_abs_path,line))
if tag:
break
@init
def grep(target,pattern):
tag=False
while True:
file_abs_path,line=yield tag
tag=False
if pattern in line:
tag=True
target.send(file_abs_path)
@init
def printer():
while True:
file_abs_path=yield
print(file_abs_path)
x=r'C:\Users\Administrator\PycharmProjects\python17期\day5\a'
g=search(opener(cat(grep(printer(),'python'))))
print(g)
g.send(x)
面向过程的程序设计:是一种流水线式的编程思路,是机械式
优点:
程序的结构清晰,可以把复杂的问题简单
缺点:
1 扩展性差
应用场景:
1 linux内核,git,httpd
模块与包
导入模块: import xxxx
或者: from xxx import 或者 from xxx import xxx as xxx 这样无非也就是起个别名
模块支持从逻辑上阻止python代码,挡代码量相当大的时候,我 们最好吧代码分成一些有组织的代码段.
前提是他们要彼此交互,
他们可能是一个累,可以是函数,这些代码是共享的.
吧其他模块加入到你的模块中的操作叫导入(import) ,那些自慰包含并具有组织代码的代码片段是模块(moudle)
- 一个Python Module(模块),是一个文件,包含了Python对象定义和Python语句(definitions and statements)。文件名就是模块名加上后缀.py,在模块内部,模块名存储在全局变量__name__中,是一个string,可以直接在module中通过__name__引用到module name。
module是为了重复使用一些对象,比如类,函数,而将这些对象定义放在一个.py文件中,或是将一个较大的工程裁缝为多个.py文件而易于维护,每一个.py文件都是一个module。


浙公网安备 33010602011771号