什么是函数
封装好的、可重复使用的代码段。
有利于代码的复用、维护,使代码更加的整洁。
函数类型
==python内置函数==,如min、max、sum、abs、map、filter、reduce等 查看内置函数
#ipython下
dir(__builtins__)
==用户自定义的函数==,如下:
#普通函数
def test(p1,p2):
print(p1,p2)
#执行
test(1,2)
#无名函数
f = lambda x:x+1
f(5) #return 6
函数的参数
==位置参数==,可以通过位置传入,也可通过关键字传入
==关键字参数==,通过关键字传入,也可以通过位置传参
==收集位置参数==,*args, args变量是一个元组
==收集关键字参数==,**kwargs,kwargs变量是一个字典
位置参数必须在关键字参数的前面!!
def test(p1,p2,verify=False,*args,**kwargs):
print(p1,p2)
print(verify)
print(args,kwargs)
#return 代表函数结束,不写return默认返回None
#执行
test(1,2,3,4,columns="sex")
#1,2
#3
#(4,) {"columns":"sex"}
局部变量与全局变量
函数内部变量查找顺序:
- 内部的局部变量
- 参数传递
- 外部的全局变量
v = 10
s = "global variable"
def test():
v = 5
s = "local variable"
print(v)
print(locals()) #{"v":5,"s":"local variable"}
print(globals())#全局变量字典
test() #5
print(v)#10
函数内部定义的变量,为局部变量,无法修改全局变量(的地址引用);
非要修改全局变量,则使用==global== 关键字声明为全局变量
v = 10
def test():
global v
v = 5
print(v)
test() # 5
print(v) #5
函数传参方式
函数的传参为==地址引用==方式
d = {"name":"jack","age":4}
s = "addr is henan"
def test(d,s):
print(id(d))
print(id(s))
test(d,s)
print(id(d),id(s)) #相同地址
函数的嵌套与闭包
函数内部,有函数
def func1():
name = "func1"
def func2():
name = "func2"
print("%s is running..."%name)
func2()
print("%s is running..."%name)
#闭包,内部函数
def func1():
name = "func1"
def func2():
print("use %s inner func2"%name)
return func2
==高阶函数==,满足条件之一,即为高阶函数
函数接收一个函数作为参数;
函数返回一个函数
map/filter/reduce
需求:使用内置函数map,将一个列表中的偶数映射为0,奇数映射为1
alist = [1,2,3,4,5,6,7]
r = map(lambda x: 0 if x%2 == 0 else 1,alist) #返回map序列对象
需求:使用内置函数filter,过滤出一个列表中的偶数
alist = [1,2,3,4,5,6,7]
r = filter(lambda x: True if x%2 == 0 else False,alist) #返回filter序列对象
需求:使用函数reduce,计算列表中所有元素的和
from functools import reduce
alist = [1,2,3,4,5,6,7]
r = reduce(lambda x,y:x+y,alist,0) #返回最后的和
#从alist中每次传进来一个值,与上一次的计算结果一同传给函数
#第一次执行时,需使用初始值
==使用内置的函数提高效率== 在有一万个随机整数的列表中,选出所有的偶数
import random
from timeit import Timer #测试性能
alist = random.randint(0,10000,10000)
def test1():
r = []
for i in alist:
if i%2 == 0:
r.append(i)
return r
def test2():
return filter(lambda x:True if x%2==0 else False,alist)
#若通过list() 转为列表,会严重影响性能
#Timer(stmt='pass', setup='pass', timer=<built-in function perf_counter>, globals=None)
#stmt, 测试语句
#setup,代码导入
#globals,全局变量字典
t1 = Timer("test1()","from __main__ import test1",globals=globals())
t1_time = t1.timeit(10000) #测试一万次
print("test1平均耗费时间%2.1f"%t1_time)
t2 = Timer("test2()","from __main__ import test2",globals=globals())
t2_time = t2.timeit(10000)
print("test2平均消耗时间%2.1f"%t2_time)
也可以使用from timeit import timeit timeit("test1()","from main import test1",number=1000,globals=globals())
函数的递归
依次调用自身,直至返回
- 递归必须有明确的结束条件
- 每执行一层就深入一层
- 效率不高,层次过深会导致栈溢出(函数调用通过压栈、弹栈实现的)
def frac(n):
if n == 1:
return 1
return n*frac(n-1)
设置断点测试-->debug-->
练习
==使用递归实现二分查找:
alist = [4,3,2,1,5,0,8]
找到则返回对应元素的索引,否则返回-1==
alist = [2,6,7,9,20]
#二分查找需有序
#需要控制好索引
def binary_search(tgt,alist,start,end):
if end < 0: #空列表
return -1
elif start == end: #只有一个元素
if tgt == alist[start]:
return start
else:
return -1
elif start < end: #多个元素
n = start + (end - start + 1)//2 #取中间值
if tgt == alist[n]:
return n
elif tgt < alist[n]: #在左边查找
return binary_search(tgt,alist,start,n-1)
else:
return binary_search(tgt,alist,n+1,end)
else:
return -1
r = binary_search(20,alist,0,len(alist)-1)
print(r)