普通函数
基本定义及调用
语法:def 函数名(参数列表):
函数体
#无参
def hello():
print("hello world")
hello()
#有参
def sum(a,b):
return a+b
print(sum(2,9))
函数标注
形参得到标注方式是在形参后面加冒号和数据类型,函数返回值的标注方法是在形参列表的def语句结尾的冒号之间加上复合符号"->"和数据类型,但注意,函数标注仅仅是标注了参数和返回值的类型,不会限定参数和返回值的类型,在函数定义和调用时,参数和返回值的类型是可以改变的。
def fun(a:str,b:str="is my favourite")->str:
s=a+" "+b
print("函数标注",fun.__annotations__)
print("传递的参数:",a,b)
return s
print(fun('python'))
#函数标注 {'a': <class 'str'>, 'b': <class 'str'>, 'return':
#<class 'str'>}
#传递的参数: python is my favourite
#python is my favourite
return语句
return[表达式]语句用于退出函数,选择性的向调用方返回一个表达式,不带表达式的return返回None
变量作用域
变量起作用的代码范围成为变量作用域。
在函数内部使用global来定义全局变量x,其同名全局变量在函数外已经定义,该变量在函数内外是同一个变量,所以在函数内部该变量所有的运算结果也反映到函数外
x,y=2,200 #全局变量
def fun():
global x
x,y=1,100 #局部变量的作用域仅在函数内部
print("函数内部: x=%d,y=%d"%(x,y))
print("函数外部: x=%d,y=%d"%(x,y))#调用函数前
fun()
print("函数外部: x=%d,y=%d"%(x,y))#调用函数后
#函数外部: x=2,y=200
#函数内部: x=1,y=100
#函数外部: x=1,y=200
在以上代码中发现,全局变量y和局部变量y是两个不同的变量,局部变量y在函数fun()调用过程中不会改变全局变量y的值,说明局部变量与全局变量名字相同,局部变量会在函数内部屏蔽同名的全局变量。
如果函数内部用global定义的全局变量在函数外部没有同名的,则调用该函数后,创建新的全局变量。
def fun1():
global c
c=90
print(c)
fun1()
print(c)
#90
#90
函数的递归调用
- 子问题需与原问题相同的问题,规模小且更简单
- 调用本身有边界条件
用递归的方式实现非负整数的阶乘
def fun(n):
if n==0:
return 1
else:
return n*fun(n-1)
print(fun(5))
#120
使用递归方式求斐波那契数列的第n个元素
def fun(n):
fn=0
if n==1:
fn=0
elif n==2:
fn=1
else:
fn=fun(n-1)+fun(n-2)
return fn
print(fun(3))
#1
匿名函数
匿名函数是没有采取使用def语句定义函数的标准方式,而用lambda方式俩简略定义的函数。匿名函数没有函数名,表达式只包含一个表达式,有以下特点:
1.表达式简洁
2.lambda表达式的主体只是一个表达式,而不是一个代码块,只能封装有限的逻辑。
3.匿名函数有自己的命名空间,不能访问自己参数列表之外或全局命名空间里的参数。
定义如下:
匿名函数名=lambda[arg1,[arg2......argn]]:expression
用匿名函数求两个数的平方差:
fun=lambda x,y:x**2-y**2
print(fun(7,6))
求1-20内偶数和的总和
fun=lambda a,b:sum(i for i in range(a,b+1)if i%2==0)
print('the sum of even numbers between {} and {} is {}'.format(1,20,fun(1,20)))
#the sum of even numbers between 1 and 20 is 110
参数传递
字符串,数字,元组是不可变对象,列表,字典是可变对象。
给参数传递不可变对象
def fun (a):
print("函数内部赋值前,变量值:",a,"变量地址:",id(a))
a+=10
print("函数内部赋值后,变量值:",a,"变量地址:",id(a))
return a
a=10
print('函数外部调用前,变量值:',a,"变量地址:",id(a))
fun(a)
print('函数外部调用后,变量值:',a,"变量地址:",id(a))
函数外部调用前,变量值: 10 变量地址: 140719143406296
函数内部赋值前,变量值: 10 变量地址: 140719143406296
函数内部赋值后,变量值: 20 变量地址: 140719143406616
函数外部调用后,变量值: 10 变量地址: 140719143406296
给参数传递可变对象
def fun (a):
print("函数内部赋值前,变量值:",a,"变量地址:",id(a))
a+=[5,6,7]
print("函数内部赋值后,变量值:",a,"变量地址:",id(a))
return a
a=[1,2,3,4]
print('函数外部调用前,变量值:',a,"变量地址:",id(a))
fun(a)
print('函数外部调用后,变量值:',a,"变量地址:",id(a))
函数外部调用前,变量值: [1, 2, 3, 4] 变量地址: 1424846803328
函数内部赋值前,变量值: [1, 2, 3, 4] 变量地址: 1424846803328
函数内部赋值后,变量值: [1, 2, 3, 4, 5, 6, 7] 变量地址: 1424846803328
函数外部调用后,变量值: [1, 2, 3, 4, 5, 6, 7] 变量地址: 1424846803328
总结:
1.不可变对象:调用函数传递不可变类型的值给a,传递的只是a的值,没有影响a本身,若在函数内部修改a的值,则生成一个新的a。
2.可变对象:调用函数传递可变类型的值给a,则是将a真正传递过去,在函数内部修改a后,函数外部的a也会收到影响。
参数类型
位置参数
顺序与数量与声明时保持一致。
关键字参数
在函数调用时,参数的传入使用了参数的名称,此类参数成为关键字参数。
注意:关键字参数必须在位置参数的后面
def fun(a,b,c):
print(a,b,c)
return
fun(1,c=2,b=3)
#1 3 2
当三个参数都是关键字参数时,顺序任意。
默认参数
在函数定义时,某个参数使用了默认值,则该函数是默认参数。
不定长参数
如果希望函数的参数不确定,则使用不定长参数,定义方式有两种:
1. *parameter
2. **parameter
前者接收多个实参并将其放入一个元组中,后者则接收键值对并将其放入字典中
def fun(*a):
sum=0
for i in a:
sum+=i
return sum
print(fun(1,2,3,4,5,6))
#21
def fun(**a):
print(a)
for k,v in a.items():
print(k,":",v)
fun(name='zhangsan',id='00001',age='19')
{'name': 'zhangsan', 'id': '00001', 'age': '19'}
name : zhangsan
id : 00001
age : 19