python函数

237 阅读4分钟

什么是函数

封装好的、可重复使用的代码段。
有利于代码的复用、维护,使代码更加的整洁。

函数类型

==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"}

局部变量与全局变量

函数内部变量查找顺序:

  1. 内部的局部变量
  2. 参数传递
  3. 外部的全局变量
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())

函数的递归

依次调用自身,直至返回

  1. 递归必须有明确的结束条件
  2. 每执行一层就深入一层
  3. 效率不高,层次过深会导致栈溢出(函数调用通过压栈、弹栈实现的)
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)

上一篇:python文件操作
下一篇:python内置函数与装饰器