1.什么是函数
具有特定功能的一段代码
2.为什么需要函数
1.复用代码
2.隐藏实现细节
3.提高可维护性
4.提高可读性便于调试
3.函数的创建与调用
def cale(a,b):
c = a + b
return c
res = cale(12,24)
print(res)
4.函数的参数传递
1.参数传递
#位置实参
def cale(a,b): # a,b称为形式参数,简称形参 形参的位置是在函数的定义出
c = a + b
return c
res = cale(12,24) # 12,24称为实际参数,简称实参 实参的位置是在函数的调用处
print(res)
#关键字传参(不会按照位置传参)
ret = cale(b = 12,a = 24)
print(ret)
2.函数调用内存分析图
在函数调用之前的内存分布:只有n1与n2
在函数调用之时的内存分布:会有arg2与arg1与n1,n2 接着arg1指向100,arg2指向n2并且追加了10元素。
在函数调用之后的内存分布:arg2与arg1内存释放,只有n1与n2.
def test(arg1,arg2):
print('arg1:id',id(arg1) , 'arg2:id',id(arg2))
print('arg1',arg1)
print('arg2', arg2)
arg1 = 100
arg2.append(44)
print('arg1:id', id(arg1), 'arg2:id', id(arg2))
print('arg1',arg1)
print('arg2', arg2)
n1 = 11
n2 = [11,22,33]
print('n1:id',id(n1) , 'n2:id',id(n2))
print("函数调用前")
print('n1', n1)
print('n2', n2)
test(n1,n2)
print("函数调用后")
print('n1', n1)
print('n2', n2)
print('n1:id',id(n1) , 'n2:id',id(n2))
'''
运行结果:
n1:id 140713557157008 n2:id 1895473373832
函数调用前
n1 11
n2 [11, 22, 33]
arg1:id 140713557157008 arg2:id 1895473373832
arg1 11
arg2 [11, 22, 33]
arg1:id 140713557159856 arg2:id 1895473373832
arg1 100
arg2 [11, 22, 33, 44]
函数调用后
n1 11
n2 [11, 22, 33, 44]
n1:id 140713557157008 n2:id 1895473373832
'''
函数调用的总结:形参名可以与实参名不一致。在函数的调用过程中,进行参数的传递:
如果是不可变对象,那么形参的操作不会影响实参的值 比如:arg1 = 100 n1还是11
如果是可变对象(列表),那么形参的操作会影响实参的值 比如:arg2.append(44) n2会增加44元素。
5.函数的返回值
def fun(num):
odd = []
even =[]
for i in num:
if i % 2: #奇数 0的布尔值为 0
odd.append(i)
else:
even.append(i) #偶数 非0的布尔值为 1
return odd,even
lis = [10,29,34,23,44,53,54]
print(fun(lis))
print(type(fun(lis)))
'''
([29, 23, 53], [10, 34, 44, 54])
<class 'tuple'>
函数返回多个值是元组类型并且元组的元素值是列表类型
'''
总结:函数的返回值
1.如果函数没有返回值[函数执行完不需要输出数据] return 可以省。
2.如果函数有一个返回值,直接返回原值。
3.如果函数有多个返回值,返回结果为元组。
#第一种情况
def fun1():
print('hello')
#第二种情况
def fun2():
return 'hello'
#第三种情况
def fun3():
return 'hello',122
fun1()
res = fun2()
print(res)
print(type(res))
ret = fun3()
print(ret)
print(type(ret))
'''
hello
hello
<class 'str'>
('hello', 122)
<class 'tuple'>
'''
6.函数的默认值
def fun1(a, b =12): # b = 12就是默认值
print('a',a)
print('b', b)
fun1(100) # 只传递a 的值 b采用默认值
fun1(100,200) # 传递a,b的值 200覆盖b的默认值
'''
a 100
b 12
a 100
b 200
'''
7.函数的可变参数
#位置形参的可变参数 (是一个元组)
def fun(*num):
print(num)
print(type(num))
fun(10)
fun(10,20)
fun(10,20,30)
#关键字形参的可变参数 (是一个字典)
def fun(**num):
print(num)
print(type(num))
fun(a= 10)
fun(a = 10,b = 20)
fun(a = 10,b = 20,c = 30)
'''
(10,)
<class 'tuple'>
(10, 20)
<class 'tuple'>
(10, 20, 30)
<class 'tuple'>
{'a': 10}
<class 'dict'>
{'a': 10, 'b': 20}
<class 'dict'>
{'a': 10, 'b': 20, 'c': 30}
<class 'dict'>
'''
一个函数位置形参的可变参数只能有一个,一个函数关键字形参的可变参数只能有一个。否则报错。
def fun(*ff,*hh): #报错
pass
def fun1(**ff,**hh): #报错
pass
def fun2(**ff,*hh): #报错
pass
def fun3(*ff,**hh): #不报错
pass
#一个函数形参可以有位置可变形参与关键字可变形参。但位置可变形参必须在前面
8.函数参数总结
实参如上1,2条总结:
#---位置传参
def fun(a,b,c):
print('a=', a)
print('b=', b)
print('c=', c)
fun(10,20,30)
list = [11,22,33]
#fun(list) 报错
fun(*list) #用*号把列表的参数分发下去
#---关键字传参
fun(a = 200, b = 56, c= 120)
dict = {'a':111,'b':222,'c':333}
#fun(dict) 不会成功
fun(**dict) #用**号把字典的参数分发下去
形参如上3,4,5,6条总结:
def fun(a,b =10): # 1.b是默认值形参
print('a', a)
print('b', b)
def fun2(*arg1): #2.形参参数可变的位置形参
print(arg1)
def fun3(**arg1): #3.形参参数可变的关键字形参
print(arg1)
def fun4(a,b,*,c,d): #4.*之后参数只能关键字传递
print('a',a)
print('b', b)
print('c',c)
print('d', d)
fun2(2,3,6,7,8,9)
fun3(a = 1,b = 12,c=23,d = 34,f = 34)
#fun4(2,2,4,5) #*之后参数只能关键字传递
fun4(2,5,c = 12,d = 222)
'''
(2, 3, 6, 7, 8, 9)
{'a': 1, 'b': 12, 'c': 23, 'd': 34, 'f': 34}
a 2
b 5
c 12
d 222
'''
总结:
9.变量的作用域
def fun(a,b):
c= a+b #a,b,c都是局部变量,只能在函数内部调用
name = 'long' #是全局变量在函数内外部都可以调用
print(name)
def fun1():
print(name)
fun1()
#在局部变量里加global相当与全局变量
def fun3():
global ss
ss = 20
fun3() #需要调用下fun3才行 直到ss有定义
dd = ss
print(dd)
10.递归函数
# 6的阶乘
def fun(n):
if(n==1):
return 1
else:
res = n*fun(n-1)
return res
print(fun(6))
'''
运行结果:720
通过调试去看运行顺序
'''
#斐波那契 第一项是1,第二项是1,从第三项开始等于前两项相加
def fib(num):
if(num == 1):
return 1
elif(num ==2):
return 1
else:
return fib(num-2) +fib(num-1)
#第六项的斐波那契值
print(fib(6))
#打印前六项的值
for i in range(1,7):
print(fib(i),end = '\t')
'''
运行结果:
8
1 1 2 3 5 8
'''