函数
基础
-
函数的作用:减少代码重复,实现代码复用
-
函数的使用步骤:
-
定义函数
def 函数名(参数): 代码1 代码2 ...
空函数
def nop(): pass # pass关键字可用来作为占位符
-
调用函数
函数名(参数)
注意:
1.参数为可选项,可有可无
2.在python中,函数必须先定义后调用,如果先调用会报错
3.如果没有调用函数,函数里面的代码不会执行
-
-
函数的参数
调用函数时,若传入的参数数量不对,或参数类型不能被函数所接受,会报
TypeError
的错误# 定义函数时同时定义接收用户的数据a,b a和b是形参 def add(a,b): res = a + b print(res) # 调用函数时调用用户的真实数据10和20,真实数据是实参 add(10,20) # 30
-
函数的返回值
在函数中,如果需要返回结果给用户需要使用函数返回值
return会返回结果给函数调用的地方
return负责函数返回值,且会退出当前函数,即导致return下方的函数体内部不执行
def sum(a,b): return a + b # 用return变量保存函数返回值 result = sum(100,50) print(result) # 50
-
函数的说明文档
函数的说明文档也叫函数的文档说明,可更方便的查看函数的注释即作用
-
定义函数的说明文档
def 函数名(参数): """说明文档的位置""" 代码 ...
-
查看函数的说明文档
help(函数名)
def sum(a,b): """求和函数""" return a + b help(sum) ''' 运行结果: sum(a, b) 求和函数 '''
-
-
函数嵌套调用
函数嵌套调用指一个函数里面又调用另外一个函数
# 1.打印多条横线 def pri_line(): print('-' * 20) def pri_lines(num): for i in range(num): pri_line() pri_lines(5) ''' 结果为: -------------------- -------------------- -------------------- -------------------- -------------------- ''' # 2.求三个数平均数 # 先求和 def sum(a,b,c): return a + b + c def avg(a,b,c): return sum(a,b,c)/3 # 调用求和函数 res = avg(10,10,10) print(res) # 10.0
进阶
-
变量作用域
变量作用域指的是变量生效的范围,主要分为两类 : 局部变量 和 全局变量
-
局部变量
所谓局部变量是定义在函数体内部的变量,即只在函数体内部生效
def test(): a = 100 print(a) test() # 100 print(a) # 报错 NameError: name 'a' is not defined
变量a是定义在
test
函数内部的变量,属于局部变量,在函数外部访问则立即报错局部变量的作用:在函数体内部,临时保存数据,即当函数调用完成后,则销毁局部变量
-
全局变量
所谓全局变量,指的是在函数体内、外都能生效的变量
# 定义全局变量a a = 100 def test(): print(a) test() # 100 def testb(): global a # 声明a为全局变量 a = 200 print(a) testb() # 200 print(a) # 200 ''' 注意: 1.如果在函数内部修改变量a,此时a并不是全局变量a的修改,而是相当于在函数内部声明一个新的局部变量 2.若想函数体内部修改全局变量,需先global声明a为全局变量,然后再重新赋值,才能修改成功 '''
-
-
返回值作为参数传递
def test1(): return 100 def test2(a): print(a) # 保存函数test1的返回值 res = test1() # 将函数test1的返回值作为参数传递到函数test2 test2(res) # 100
-
函数的返回值
若遇到一个函数有多个返回值的情况,应采用
retrun a,b
的写法def test(): return 1,2 res = test() print(res) # (1,2)
return a,b
的写法,返回多个数据的时候,默认是元组类型- return后可以连接列表、元组或字典,以返回多个值
-
函数的参数
-
位置参数
调用函数时根据函数定义的参数位置来传递参数
传递和定义参数的顺序和个数必须一致
def user(name,age): print(f'您的姓名是{name},年龄是{age}') user('Tom',21) user('Tom') # 报错 个数定义和传递不一致 TypeError:user() missing a required psitional argument:'age'
-
关键字参数
函数调用,通过
key=value
的键值对形式加之指定。可以让函数更加清晰、容易使用,同时消除参数的顺序要求def user(name,age): print(f'您的姓名是{name},年龄是{age}') user('Tom',21) # 您的姓名是Tom,年龄是21 user(age=21,name='Tom') # 您的姓名是Tom,年龄是21
函数调用时,如果有位置参数,位置参数必须在关键字参数的前面,但关键字参数之间不存在先后顺序
-
缺省参数
缺省参数也称为默认参数,用于定义函数,为参数提供默认值,调用函数时可不传递该默认参数的值(注:所有位置参数必须出现在默认参数前,包括函数定义和调用)
def user(name,age=16): print(f'您的姓名是{name},年龄是{age}') user('Tom',21) # 您的姓名是Tom,年龄是21 user('Tom') # 您的姓名是Tom,年龄是16
注意:函数调用时,如果为缺省参数传值则修改默认参数值;否则使用默认值
-
不定长参数
不定长参数也称为可变参数。用来解决不确定嗲用时需要传递多少个参数(包括不传参)的情形。这种情形下,可用包裹(packing)位置参数,或包裹关键字参数,来进行参数传递。
包裹位置传递
def user(*args): print(args) user(11) # (11,) user(11,14) # (11,14) user() # ()
注意:包裹位置传递采用
*args
,传递的所有参数都会被args参数收集,他会根据传进参数的位置合并为一个元组,args是元组类型。包裹关键字传递
def user(**kwargs): print(kwargs) user(name='Tom',age=18,id=1001) # {'name':'Tom','age':18,'id':1001}
包裹关键字传递采用
**kwargs
,kwargs是字典类型无论是包裹位置传递还是包裹关键字传递,都是一个组包的过程,即收集零散数据,返回一个整体
-
-
拆包
-
拆包:元组
def test(): return 1,2 a,b = test() # 拆包 print(a) # 1 print(b) #2
-
拆包:字典
dict1 = {'name':'Tom','age':18} a,b = dict1 # 对字典进行拆包,取出来的是字典的key print(a) # name print(b) # age print(dict[a]) # Tom print(dict[b]) # 18
-
-
交换变量值
# 有变量a = 10 和b = 20,交换两个变量的值 # 方法一:借助第三变量存储数据 a,b = 10,20 # 1.定义中间变量c c = 0 # 2.将a的数据存储到c c = a # 3.将b的数据20赋值到a,此时a = 20 a = b # 4.将c的数据10赋值到b,此时b = 10 b = c print(a) # 20 print(b) # 10 # 方法二: a,b = 10,20 a,b = b,a print(a) # 20 print(b) # 10
-
引用
在python中,值是依靠
引用
来传递的id():判断两个变量是否为同一个值的引用,可将id理解为内存的地址标识
# 1. int类型 不可变类型 a = 1 b = a print(b) # 1 # a和b的id值相同 print(id(a)) # 2081153024240 print(id(b)) # 2081153024240 a = 2 print(b) # 1 说明int类型为不可变类型 # 修改a的值,内存要开辟另一块内存存储2,id检测到a和b的地址不同 # 2.列表类型 可变类型 c = [1,2] d = c print(d) # [1,2] print(id(c)) # 1896861660480 print(id(d)) # 1896861660480 c.append(20) print(c) # [1, 2, 20] print(id(c)) # 1896861660480 print(id(d)) # 1896861660480 # id值相同,且与修改数据之前相同
引用可以当做实参使用
不可变类型计算前后id值不同
可变类型计算前后id值相同
可变类型:
- 列表
- 字典
- 集合
不可变类型:
- 整型
- 浮点型
- 字符串
- 元组
递归
递归是一种编程思想,在函数内部,可以调用其他函数,如果函数在内部调用其自身,该函数就是递归函数
-
特点:
- 函数内部自己调用自己
- 必须有出口
-
示例:
# 计算n! def fact(n): if n == 1: return 1 else: return n * fact(n-1) print(fact(3)) # 6 正确
-
注意:
使用递归函数需要注意防止栈溢出,在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出。
解决递归调用栈溢出的方法是通过尾递归优化,事实上尾递归和循环的效果是一样的,所以,把循环看成是一种特殊的尾递归函数也是可以的。
尾递归是指,在函数返回的时候,调用自身本身,并且,return语句不能包含表达式。这样,编译器或者解释器就可以把尾递归做优化,使递归本身无论调用多少次,都只占用一个栈帧,不会出现栈溢出的情况。
lambda表达式
如果一个函数有一个返回值,且只有一句代码,可使用lambda简化
-
lambda语法
lambda 参数列表 : 表达式
lambda表达式的参数可有可无,函数的参数在lambda表达式中完全适用
lambda表达式能接收任何数量的参数但只返回一个表达式的值
# 函数 def fn1(): return 100 print(fn1) # <function fn1 at 0x000002C802233E20> print(fn1()) # 100 # lambda表达式 fn2 = lambda : 200 print(fn2) # <function <lambda> at 0x000002C80234E8C0> print(fn2()) # 200 # 直接打印lambda表达式,输出的是lambda的内存地址
-
参数
-
无参数
f = lambda : 100 print(f())
-
单参数
f = lambda a : a print(f(1)) # 1
-
默认参数
f = lambda a,b,c = 100 : a + b + c print(f(1,2)) # 103
-
可变参数:*args
f = lambda *args : args print(f(10,20)) # (10,20)
-
可变参数:**kwargs
f = lambda **kwargs : kwargs print(f(name='python',age=10)) # {'name':'python','age':10}
-
-
lambda应用
# 带判断的lambda f = lambda a,b : a if a > b else b print(f(10,50)) # 50 # lambda表达式支持三目运算符
高阶函数
把函数作为另一个函数的参数传入,这样的函数称为高阶函数,高阶函数是函数式编程的体现。函数式编程是指高度抽象的编程范式。
abs(100)
是函数调用,而abs
是函数本身函数本身也可以赋值给变量,即变量可以指向函数
变量可指向函数,而函数的参数能接收变量,所以一个函数可以接收另一个函数作为参数,此函数称之为高阶函数
# abs() 绝对值
abs(-10) # 10
# round() 四舍五入计算
round(3.6) # 4
# 任意两个数字,按照指定要求整理数字后在进行求和计算
# 绝对值后进行求和计算
# 方法一:
def add(a,b):
return abs(a) + abs(b)
print(add(1,-10)) # 11
# 方法二:
def sum(a,b,f):
return f(a) + f(b)
res = sum(1,-10,abs)
print(res) # 11
res1 = sum(1.1,2.1,round)
print(res1) # 3
map/reduce
python内置函数map()
和reduce()
map()
map()函数接收两个参数,一个是函数,一个是Iterable
,map()将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator(迭代器)
返回
def f(x):
return x * x
r = map(f,[1,2,3,4])
list(r)
# [1,4,9,16]
reduce()
reduce()函数把一个函数作用在一个序列上,这个函数必须接收两个参数,reduce把结果继续和序列的下一个元素做累积计算
注意:reduce()传入的参数func必须接收2个参数
# reduce(f,[x1,x2,x3,x4]) = f(f(f(x1,x2),x3),x4)
del add(x,y):
return x + y
reduce(add,[1,3,5,7,9]) # 25
# 将序列[1,3,5,7,9]变换成整数13579
del f(x,y):
return x * 10 + y
reduce(f,[1,3,5,7,9]) # 13579
filter
python内置的filter()函数用于过滤序列,过滤掉不符合条件的元素,返回一个filter对象,若要转换为列表,可使用list()转换
和map()类似,filter()接收一个函数和一个序列,filter()把传入的函数依次作用于每个元素,然后根据返回值是True还是False决定保留还是丢弃该元素
# 在一个list中,删除偶数,保留奇数
def is_ok(n):
return n % 2 == 1
print(list(filter(is_ok,[1,2,3,4,5,6,7,8,9])))
# [1, 3, 5, 7, 9]
sorted
=sorted(list,key= ,reverse= )
python内置的sorted()函数可对list进行排序
sorted([36, 5, -12, 9, -21])
# [-21, -12, 5, 9, 36]
sorted()函数作为高阶函数,可接收一个key
函数来实现自定义排序,其关键在于实现一个映射函数
其中,key指定的函数将作用于list的每个元素上,并根据key函数返回的结果进行排序,并按照对应关系返回list相应的元素
第三个参数reverse=True可进行反向排序
# sorted()
sorted([36, 5, -12, 9, -21])
# [-21, -12, 5, 9, 36]
# sorted()作为高阶函数,实现自定义排序
# 按绝对值大小排序
sorted([36, 5, -12, 9, -21], key=abs)
# [5, 9, -12, -21, 36]
# 对该列表按名字排序
L = [('Bob', 75), ('Adam', 92), ('Bart', 66), ('Lisa', 88)]
def by_name(t):
return t[0]
L2 = sorted(L, key=by_name)
print(L2) # [('Adam', 92), ('Bart', 66), ('Bob', 75), ('Lisa', 88)]
# 按成绩从高到底排序
def by_score(t):
return -t[1]
L3 = sorted(L, key=by_score)
print(L3) # [('Adam', 92), ('Lisa', 88), ('Bob', 75), ('Bart', 66)]