1、函数的特点
- 函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段。
- 主要用于封装语句,让程序更加模块化,提高代码的重用性。
- 用于定义用户级别的函数。
2、函数的定义
- 函数代码块以 def 关键词开头,后接函数标识符名称和圆括号 ()。
- 任何传入参数和自变量必须放在圆括号中间,圆括号之间可以用于定义参数。
- 函数的第一行语句可以选择性地使用文档字符串—用于存放函数说明。
- 函数内容以冒号 : 起始,并且缩进。
- return [表达式] 结束函数,选择性地返回一个值给调用方,不带表达式的 return 相当于返回 None。
- 注意:
- 函数的名字就是语句块的名称
- 函数名的命名规则与变量名相同(函数名必须是标识符)
- 函数名是一个变量
- 函数有自己命名空间,在函数外部不可以访问函数内部的变量, 函数内部可以访问函数外部的变量,但不能修改函数外部变量的帮绑定关系,要让函数处理外部数据需要用参数给函数传入一些数据。
- 参数列表可以为空,
- 语句部分不能为空,如果为空需要用pass语句填充
#1、函数名是变量,它在创建时绑定一个函数。
def f1():
print("hello f1")
def f2():
print("hello f2")
fx = f1 #注意此处f1没有() 函数也是对象可以被绑定
fx() #hello f1
f1() #hello f1
f1 = f2 #让f1改变绑定关系,去绑定f2
f1() #调用f2
#函数交换赋值
f1,f2 = f2,f1
f1() #hello f2
f2() #hello f1
#2、一个函数可以作为另一个函数实参传递
def f1():
print("f1被调用")
def f2():
print("f2被调用")
def fx(fn):
print("fn绑定的是:",fn)
fn()#调用fn绑定的函数
fx(f1)
fx(f2)
运行结果:
fn绑定的是: <function f1 at 0x00000171603D2E18>
f1被调用
fn绑定的是: <function f2 at 0x0000017160737C80>
f2被调用
#3、函数作为另一个函数的返回值
def get_op():
s = input("请输入你要做的操作:")
if s == "求最大":
return max
elif s == "求最小":
return min
elif s == "求和":
return sum
L = [1,2,3,4]
fx = get_op()
print(fx(L))
#4、函数的嵌套定义
#在一个函数内用def语句创建其他函数
def fun_outer():
print("fun_outer被调用。。。")
#在此处创建另外一个函数
def fun_inner():
print("fun_inner被调用...")
fun_inner() #调用
print("fun_outer调用结束")
fun_outer()
运行结果:
fun_outer被调用。。。
fun_inner被调用...
fun_outer调用结束
3、函数调用
- 语法: 函数名(实际调用传递参数)
- 注意:函数调用是一个表达式
- 如果没有return语句,函数执行完毕后返回None对象
- 如果函数需要返回其他的对象需要用到return语句
# 定义函数
def printme( str ):
# 打印任何传入的字符串
print (str)
return
# 调用函数
printme("我要调用用户自定义函数!")
printme("再次调用同一函数")
运行结果:
我要调用用户自定义函数!
再次调用同一函数
- return 语句;
- 语法: return 【表达式】
- 注:[ ] 代表内容可省略
- 作用:
- 用于函数中,结束当前的函数的执行,返回到调用该函数的地方
- 同时返回表达式的引用关系。
- 说明:
- return 语句后跟的表达式可以省略,省略后相当于return None
- 如果函数内没有return语句,则函数执行完最后一条语句后返回None
4、函数的参数传递
- 4.1 不可变对象实例和可变对象实例
- 形参和实参指向的是同一个对象(对象 id 相同),在函数内部修改形参后,形参指向的是不同的 id。
- 可变对象在函数里修改了参数,那么在调用这个函数的函数里,原始的参数也被改变了。
#不可变对象实例传参
def change(a):
print(id(a)) # 指向的是同一个对象
a=10
print(id(a)) # 一个新对象
a=1
print(id(a))
change(a)
运行结果:
4379369136
4379369136
4379369424
# 可变对象
def changeme( mylist ):
"修改传入的列表"
mylist.append([1,2,3,4])
print ("函数内取值: ", mylist)
return
# 调用changeme函数
mylist = [10,20,30]
changeme( mylist )
print ("函数外取值: ", mylist)
运行结果:
函数内取值: [10, 20, 30, [1, 2, 3, 4]]
函数外取值: [10, 20, 30, [1, 2, 3, 4]]
- 4.2 传递方式:
- 位置传参 位置参数须以正确的顺序传入函数。
- 序列传参
- 关键字传参
- 字典关键字传参
- 默认传参
- 位置传参(序列传参):实际传递参数(实参)与形式参数(形参)的对应关系位置来一次对应
#位置传参
def func(a,b,c ):
print(a)
print(b)
print(c)
# 调用函数
func(1,2,3)
运行结果:
1
2
3
- 序列传参:按照顺序传递
#序列传参
def myfun(a,b,c):
print("a = ",a)
print("b = ",b)
print("c = ",c)
a = 'bcd'
myfun(*a)
运行结果:
a = b
b = c
c = d
- 关键字传参: 按照名称进行分配
- 关键字参数和函数调用关系紧密,函数调用使用关键字参数来确定传入的参数值。
- 使用关键字参数允许函数调用时参数的顺序与声明时不一致,因为 Python 解释器能够用参数名匹配参数值。
#可写函数说明
def printinfo( name, age ):
"打印任何传入的字符串"
print ("名字: ", name)
print ("年龄: ", age)
return
#调用printinfo函数
printinfo( age=50, name="runoob" )
运行结果:
名字: runoob
年龄: 50
- 字典关键字传参:**字典
- 字典的键名和形参名必须一致
- 字典的键名必须为字符串(且必须为标识符的规则)
- 字典的键名要在形参中存在
diction = {"a":50,"b":20,"c":50}
def myfun(d,a,b,c):
print("a = ",a)
print("b = ",b)
print("c = ",c)
print("d = ",d)
myfun(20,**diction)
- 默认参数:调用函数时,如果没有传递参数,则会使用默认参数。
#可写函数说明
def printinfo( name, age = 35 ):
"打印任何传入的字符串"
print ("名字: ", name)
print ("年龄: ", age)
return
#调用printinfo函数
printinfo( age=50, name="runoob" )
print ("------------------------")
printinfo( name="runoob" )
- 综合传参 要求:位置传参在前,关键字传参在后
- 缺省实参 eg:def info(name,age=1,address="未填写")
- 规则:
- 1、缺省参数必须自右至左依次存在,如果一个参数有缺省参数,则其右侧的所有参数都必须有缺省参数。
- 2、缺省参数可以有0个或多个
5、 函数形参的定义方式:
- 位置形参
- 星号元组形参
- 命名关键字形参
- 双型号字典形参
- 位置形参
- 语法: def 函数名(形参名1,形参名2,.....):
- 语句块
def info(name,age = 1,address="未知"):
print(name,'今年',age,'岁,住在',address)
info('小明',25,'beijing',12)
d = [1,2,3,4,5]
- 星号元组形参:
- 语法: def 函数名(* 元组形参名):
- 语句块
- 作用:收集多余的位置传参
def mysum(*args):
Sum = 0
for i in args:
Sum = i + Sum
return Sum
d = mysum(1,2,3,4)
print(d)
- 命名关键字形参 https://blog.csdn.net/yilovexing/article/details/80577510
- 语法: def 函数名(*,命名关键字形参):
- 语句块
- 或 def 函数名(*args,命名关键字形参):
- 语句块
- 作用:强制所有的传参都必须用关键字传参。
- 加了星号 * 的参数会以元组(tuple)的形式导入,存放所有未命名的变量参数。
- 如果在函数调用时没有指定参数,它就是一个空元组。
- 如果单独出现星号 * 后的参数必须用关键字传入。
#eg:关键字形参
def fa(a,b,*arg,c,d):
#强制c,d必须使用关键字传参
print(a,b,c,d)
print(arg)
fa(1,2,10,20,d=400,c=300)
运行结果:
1 2 300 400
(10, 20)
#fa(1,2,3,4)错误
- 双星号字典形参
- 语法:def 函数名(** 字典形参名)
- 语句
- 作用:收集多余的关键字传参
#双星号字典形参的用法。
def fa(**kwargs):
print("多余的关键字传参个数是:",len(kwargs))
print("kwargs=",kwargs)
fa(a=10,b=20,c=50)
运行结果:
多余的关键字传参个数是: 3
kwargs= {'a': 10, 'b': 20, 'c': 50}
函数参数自左至右的顺序是:
位置形参 - 星号元组形参-命名关键字形参-双星号形参
6、强制位置参数
- Python3.8 新增了一个函数形参语法 / 用来指明函数形参必须使用指定位置参数,不能使用关键字参数的形式。
- 在以下的例子中,形参 a 和 b 必须使用指定位置参数,c 或 d 可以是位置形参或关键字形参,而 e 或 f 要求为关键字形参:
def f(a, b, /, c, d, *, e, f):
print(a, b, c, d, e, f)
f(10, 20, 30, d=40, e=50, f=60)
错误示范:
f(10, b=20, c=30, d=40, e=50, f=60) # b 不能使用关键字参数的形式
f(10, 20, 30, 40, 50, f=60) # e 必须使用关键字参数的形式
7、匿名函数
- lambda 表达式(又称匿名函数)
- 作用: 创建一个匿名函数对象
- 同def类似,但不提供函数名。
- 语法格式: lambda[形参1,形参2,....]:表达式
- eg: myadd = lambda a,b : a+b
- 1、lambda只是一个表达式,他用来创建一个函数对象
- 2、当lambda表达式调用时,先执行冒号(:)后的表达式,并返回表达式的结果的引用。
- 3、lambda表达式创建的函数只能包含一条表达式(不能是语句),lambda比函数简单而且可以随时创建和销毁,有利于减少程序的耦合度
#lambda创建匿名函数
myadd = lambda a,b:a+b
print("10+20=",myadd(10,20))
运行结果:
10+20= 30
#lambda传参
def fx(f,x,y):
print(f(x,y))
fx(lambda a,b:a+b,100,200)
运行结果:
300
8、函数式编程
- 定义:是指用一系列函数解决问题
- 函数是一等公民(Guido)
- 1、函数本身可以赋值给变量,赋值后变量绑定函数
- 2、允许将函数本身作为参数传入另一个函数
- 3、允许函数返回一个函数
- 好处:
- 用每一个函数完成细小的功能,一系列函数在任意组合完成大问题
- 函数的可重入性:
- 当一个函数在运行时不读取和改变除局部作用域意外的变量时,此函数为可重入函数
- 可重入函数在每次调用时,如果参数一定,结果必然一定。
#示例可重入函数
def add1(x,y):
return x+y
#不可重入函数
y = 200
def add2(x):
return x + y
print(add2(10))
y = 300
print(add2(10))
9、高阶函数 high order function
- 满足下列条件中一个的函数即为高阶函数
- 1、函数接收一个或多个函数作为参数传入
- 2、函数返回一个函数
- 注:python中内建的高阶函数:map,filter,sorted
- map 函数
- map(func,*iterables)用函数和对可迭代对象中的每一个元素作为参数返回新的可迭代对象,当最短的一个可迭代对象不再提供数据时迭代结束。
- 要求:func函数接收的参数个数必须与可迭代对象的个数相同
#map示例
def power2(x,y):
return x ** y
#生成一个可迭代对象,
#此可迭代对象可以生成1~9自然数的平方根
for x in map(power2,range(1,10),range(1,10)):
print(x)
结果:
1
4
27
256
3125
46656
823543
16777216
387420489
- filter函数(过滤器)
- 格式:filter(function,iterable)
- 作用:筛选可迭代对象iterable中的数据,返回一个可迭代对象,此可迭代对象将对iterable提供的数据进行筛选。
- 说明:函数function将对iterable中的每个元素进行求布尔值,返回True这保留,返回False则丢弃。
#filter.py(过滤器)
def is_odd(x):
return x%2 == 1
for x in filter(is_odd,range(41,53)):
print(x)
结果:
41
43
45
47
49
51
- sorted函数(排序)
- 作用:将原可迭代对象提供的数据进行排序,生成排序后的列表
- 格式:sorted(iterable,key=None,reverse=False)
- 说明:iterable(可迭代对象)
- key 函数是用来提供一个排序参考值的函数,这个函数的返回值将作为排序的依据
- reverse 标志用来设置是否降序排序
L = [5,-2,-4,0,3,1]
L2 = sorted(L,key=abs)
print(L2)
结果:
[0, 1, -2, 3, -4, 5]
10、递归函数 recursion
- 函数直接或间接的调用自身
#直接递归
def f():
f()
f()
#间接递归
def fa():
fb()
def fb():
fa()
fa()
- 说明:递归一定要控制递归的层数,当符合一定条件要终止递归调用
- 几乎所有的递归都能用while循环来代替
- 优点:递归可以把问题简单化,让思路更为清晰,代码简洁
- 缺点:递归因系统环境影响大,当递归深度太大时,可能会得到不可预知的结果
- 递归的两个阶段:
- 递推阶段:从原问题出发,按递归公式递推从未知到已知,最终达到递归的终止条件
- 回归阶段:按递归终止条件求出结果,逆向逐步代入递归公式,回到问题求解。
#示例:利用递归求n的阶乘
def myfac(n):
if n == 1:
return n
else:
return n * myfac(n-1)
k = myfac(5)
print(k)
#递归求和
def mysum(n):
if n == 1:
return 1
return n + mysum(n-1)
print(mysum(100))
运行结果:5050
11、闭包 closure
- 闭包是指引用了此函数外部嵌套函数作用域变量的函数
- 闭包必须满足的三个条件:
- 1、必须有内嵌函数
- 2、内嵌函数必须引用外部函数中的变量
- 3、外部函数返回值必须是内嵌函数。
def make_power(y):
def fn(x):
return x**y
return fn
pow2 = make_power(2)
print('5的平方是:',pow2(5))