一句废话都没有的Pycharm(十):函数
介绍:
- 1.函数的创建和调用
- 2.函数的参数传递
- 3.函数的返回值
- 4.函数的参数定义
- 4.1默认值参数
- 4.2个数可变的位置形参
- 4.3个数可变的关键字形参
- 4.4函数调用时的参数传递
- 5.变量的作用域
- 6.递归函数
骨骼图:
1.函数的创建和调用
函数就是执行特定任务和完成特定功能的一段代码,例如之前用到的type()
函数是用来查询元素类型的,id()
函数用来查询元素的内存地址。
函数的使用给编码带来了极大的便利:
- 重复使用函数
- 隐藏实现细节
- 提高可维护性
- 提高可读性和便于调试
创建语法:
def 函数名(参数):
函数体
[return xx]
调用语法:
变量名=函数名(参数)
print(变量名)
合法函数名只能包含字母数字下划线。
代码演示:
#函数的创建及调用
def multiply(a,b):
c=a*b
return c
result=multiply(2,3)
print(result)
结果:
2.函数的参数传递
参数的传递有两种方式:
- 位置实参
- 关键字实参
首先我们先明确几个名称:
形式参数(形参): 上面代码def multiply(a,b):
中的a和b就是形式参数,没有任何实值意义。(它类似于线性代数中我们所说的抽象代数)与此相对的就是:
实值参数(实参): 上面代码中result=multiply(2,3)
的2和3,就是实值参数,它具有具体的数值意义。
对于第一种传参方式(位置实参):
就是根据位置,把实参传给形参。即:把2传给a,3传给b。
对于第二种传参方式(关键字实参):result=multiply(b=2,a=3)
根据关键字a,b进行传参,即,将2传给b,3传给a(而不是通过位置)。
例2.1:
代码:
#传参方式
#位置实参,
def pow(a,b):
c=a**b
return c
result=pow(2,3)#把2传给a、3传给b
print(result)#2的3次方是8
#关键字实参
result=pow(b=2,a=3)#把2传给b、3传给a
print(result)#3的2次方是9
结果:
另外强调一点,在函数调用过程中,关于参数的传递:在函数体内修改不可变对象,不会影响实参的值;在函数体内修改可变对象,会影响实参的值。
例2.2:
def fun(a1,a2):
a1=100;#将b1传进来的10改为100
a3=[1,2]#给b2传进来的列表后追加1,2
a2.extend(a3)
b1=10
b2=[5,6,7]
print('b1',b1)#b1 10
print('b2',b2)#b2 [5, 6, 7]
fun(b1,b2)
print('b1',b1)#b1 10。int型数据是不可变对象
print('b2',b2)#b2 [5, 6, 7, 1, 2]。列表是可变对象
结果:
3.函数的返回值
- 当函数没有返回值时,不用写return,如例2.2中的函数代码。
- 当函数有一个返回值时,直接return返回类型,如例2.1中的函数代码。
- 当函数有多个返回值时,返回结果为元组。
例如:
#当函数有多个返回值时,返回结果为元组
def classification(lis):
odd=[]#奇数
even=[]#偶数
for i in lis:
if i%2:
odd.append(i)
else:
even.append(i)
return odd,even
#函数调出
list=[1,55,66,45,43,44,52,90,88,0]
print(classification(list))
结果:
返回结果为元组,元组内第一个列表存储的是奇数,第二个列表存储的是偶数。
4.函数的参数定义
4.1默认值参数:def fun(a,b=1)
这里的b=1就是默认参数值,当只传进来一个实参时,如fun=(900)
:这个900传给a;当传进来两个实参时,如fun(2,3)
:2传给a,3传给b,此时默认值被替换。
代码:
#默认值参数
def fun1(a,b=1):
return a,b
print(fun1(900))#(900,1)
print(fun1(2,3))#(2,3)
结果:
4.2个数可变的位置形参
在创建参数时,事先不知道所需传参位置形参的个数,因此使用个数可变的位置参数,使用*参数名
,如:def fun1(*nums)
,结果为一个元组。
注:可变的位置参数只能定义一个,否则会报错。
代码:
#个数可变的位置参
def fun2(* nums):
print(nums)
fun2(11)
fun2(11,22,31)
fun2(1,3,4,5,6,6)
结果:
4.3个数可变的关键字形参
在创建参数时,事先不知道所传关键字实参的个数,因此使用可变的关键字形参,使用**参数名
,如:def fun2(**nums)
,结果为一个字典。
注:可变的关键字形参只能定义一个,否则会报错。
代码:
#个数可变的关键字形参
def fun3(** nums):
print(nums)
fun3(a=11)
fun3(a=11,b=22,c=31)
fun3(a=1,b=3,c=4,d=5,f=6)
结果:
如果创建的函数既有个数可变的位置形参又有个数可变的关键字形参,其定义必须如def fun(*a,**b)
,即个数可变的位置参数在个数可变的关键字形参之前。否则会报错。
4.4函数调用时的参数传递
当我们想把一个序列的每一个元素转化为位置实参传入函数时,我们需要用到*
;当我们想把一个字典的每一个键值对转化为关键字实参传入函数时,我们需要用到**
。
如:
def func(a,b,c):
print('a=',a,end='\t')
print('b=',b,end='\t')
print('c=',c,end='\t')
print(end='\n')
list1=[1,2,3]
func(*list1)#把一个序列的每一个元素转化为位置实参传入函数func()
dic={'a':1,'b':2,'c':3}
func(**dic)#把一个字典的每一个键值对转化为关键字实参传入函数
结果:
关键字参数传递: 当在传参数时,我们希望funct(1,2,c=34,d=58)
c和d都用关键字传(a,b是位置传参),因此需要这样创建函数def funct(a,b,*,c,d)
,“*”之后的采用关键字传参。
代码:
#关键字参数传递
def funct(a,b,*,c,d):
print('a=', a, end='\t')
print('b=', b, end='\t')
print('c=', c, end='\t')
print('d=', d, end='\t')
print(end='\n')
funct(1,2,c=29,d=90)
结果:
5.变量的作用域
- 局部变量:在函数体内定义的变量,只对函数内有效,使用global声明后,可变为全局变量。
- 全局变量:在函数体外定义的变量,对函数内外都有效。
代码:
#变量的作用域
def function(a,b): #a,b,c 均为局部变量
c=a-b
print(c)
num1=4
num2=5
print(num1,num2)
function(num1,num2)#num1,num2为全局变量
#print(c)#因为c为局部变量,在函数外无定义,所以报错。NameError: name 'c' is not defined
def function(a,b): #a,b,c 均为局部变量
global c #用global声明后,可变为全局变量
c=a-b
print(c)
num1=4
num2=5
print(num1,num2)
function(num1,num2)#num1,num2为全局变量
print(c)#用global声明后,c为全局变量,在函数体外存在,可输出
结果:
6.递归函数
在一个函数的函数体内调用了该函数本身。递归函数必须要有递归终止条件,每递归一次都会在栈内分配一次栈帧,用完之后自动释放相应的空间。因此它的缺点是占内存多,效率低,但是它便于理解。
例子:递归求阶乘
代码:
#递归函数求阶乘
def factorial(n):
if n==1:
return 1
else:
return n*factorial(n-1)
print(factorial(6))
结果:
例子:递归函数输出斐波那契数列
斐波那契数列指的是这样一个数列:0、1、1、2、3、5、8、13、21、34、…… 在数学上,斐波那契数列以如下被以递推的方法定义:F(0)=0,F(1)=1, F(n)=F(n - 1)+F(n - 2)(n ≥ 2,n ∈ N*)
代码:
#递归函数输出斐波那契数列
def Fibonacci(i):
if i==0:
return 0
elif i==1:
return 1
else:
return Fibonacci(i-1)+Fibonacci(i-2)
fibonacci=[]
for i in range(0,10):#输出0-10的斐波那契数列
t=Fibonacci(i)
fibonacci.append(t)
print(fibonacci)
结果: