一、函数介绍
编程方式
1、面向对象---类---定义关键字:class
2、面向过程---过程---定义关键字:def
3、函数式编程---函数---定义关键字:def
函数定义
数学中函数的定义,如:y=2x,(x为自变量,y为因变量,y的值会随着x的变化而变化)
编程中函数的定义:函数是逻辑结构化和过程化的一种编程方法。
函数的创建、调用
def func1():
print("第一个函数的代码块")
return 0
a=func1()
>>>
第一个函数的代码块
过程的创建、调用
def func2():
print("第二个函数的代码块")
b=func2()
>>>
第二个函数的代码块
面向过程与面向函数的过关系:过程就是没有返回值得函数,但在python中其实没有过程的概念,因为过程返回值为None
def func1():
print("第一个函数的代码块")
return 0
def func2():
print("第二个函数的代码块")
print("func1返回值:%s"%func1())
print("func2返回值:%s"%func2())
>>>>>>>>>>
func1返回值:0
func2返回值:None
函数的作用
1、代码重复利用
2、可扩展
3、保持一致性(只要改一处,调用该函数的地方都会跟着改变)
返回值
返回值的作用:
1、结束函数 (函数在执行过程中,遇到return就停止);
2、返回一个值/结果 (若没指定返回值,则返回none)
def func1():
print("test1")
return 0
print("test2")
a=func1()
print(a)
>>>>>>>>>
test1
0
返回值的个数、类型:
def test1():
print('test1')
def test2():
print('test2')
return 0
def test3():
print('test3')
return 0,1,"hello",[1,2],{"age":11}
x=test1()
y=test2()
z=test3()
print(x)
print(y)
print(z)
>>>>>>>>>>>>>>>>>>
test1
test2
test3
None
0
(0, 1, 'hello', [1, 2], {'age': 11})
总结:
返回值个数=0,返回None;
返回值个数=1,返回object;
返回值个数>1,返回元组
参数及调用
形参:函数创建和定义过程中小括号里的参数
实参:函数被调用的过程中传递进来的参数
三种参数形式:位置参数、关键字参数、默认参数
位置参数:普通的实参(直接给出参数值,系统默认与形参一一对应)。
默认参数:函数定义的时候为形参赋予默认值(函数调用时,可以省略实参也可以给该形参赋值)
关键字参数:函数调用的时候,通过参数名指定要赋值的参数
位置参数调用:与形参一一对应
def test(x,y):
print(x)
print(y)
test(1,2)
>>>>>>
1
2
关键字参数调用:与形参顺序无关
def test(x,y):
print(x)
print(y)
test(y=2,x=1)
>>>>>
1
2
位置参数、关键字参数2者混合调用:关键参数不能写在位置参数前面
默认参数的调用:函数调用的时候,默认参数的值非必填
概念:定义形参的时候,被直接赋值的形参叫做默认参数
作用:提前固定值,如默认安装软件
def test(x,y=2):
print(x)
print(y)
test(1)
test(1,4)
>>>>> 1 2
>>>>> 1 4
位置参数、关键字参数、默认参数的特点:
调用时,实参给的个数小于or大于形参的个数,程序会报错
非固定参数及调用(参数组)
实参数目不固定,形参如何定义?
*args参数组:接收n个位置参数,并转换成元组的方式
def test(*args):
print(args)
test(1,2,3,4,5)
>>>>>>
(1,2,3,4,5) #返回一个元组
def test(*args):
print(args)
test(*[1,2,3,4,5]) #args=tuple([1,2,3,4,5])
>>>>>>
(1,2,3,4,5)
组合(位置参数、*args参数组):
def test(x,*args):
print(x)
print(args)
test(1,2,3,4,5)
>>>>>>
1
(2, 3, 4, 5)
**kargs参数组:接收n个关键字参数,转换成字典的方式
def test(**kwargs):
print(kwargs)
test(name="jack",age=8,sex="m")
>>>>>>
{'name': 'jack', 'age': 8, 'sex': 'm'}
def test(**kwargs):
print(kwargs)
test(**{'name': 'jack', 'age': 8, 'sex': 'm'})
>>>>>>>
{'name': 'jack', 'age': 8, 'sex': 'm'}
组合(位置参数、**kwargs参数组):
def test(x,**kwargs):
print(x,kwargs)
test("hello",name="jack",age=8,sex="m")
>>>>>>
hello {'name': 'jack', 'age': 8, 'sex': 'm'}
组合(位置参数、默认参数、**kwargs参数组):
def test(x,y=11,**kwargs):
print(x)
print(y)
print(kwargs)
test("hello",name="jack",age=8,sex="m")
>>>>>
hello
11
{'name': 'jack', 'age': 8, 'sex': 'm'}
组合(位置参数、默认参数、*args、**kwargs参数组):
def test(x,y=11,*args,**kwargs):
print(x)
print(y)
print(args)
print(kwargs)
test("hello",name="jack",age=8,sex="m")
>>>>>>>>>
hello
11
()
{'name': 'jack', 'age': 8, 'sex': 'm'}
作用域
局部变量:在子程序/函数中定义的变量
作用域:
1、只在局部范围生效,如函数定义中申明的变量,则该函数是这个变量的作用域
2、若想改变作用域,需加关键字 global,则作用域是整个程序(不推荐使用,容易导致逻辑混乱)
全局变量:在程序一开始定义的变量
作用域:在整个程序中生效
两者关系:若两者变量名相同,在定义局部变量的子程序内,局部变量起作用;在其他地方,全局变量起作用
递归
概念:函数调用自身的行为
递归的两个条件:
(1)、调用函数本身
(2)、设置了正确的返回条件
总结:
(1)必须要有一个明确的结束条件。
(2)每次进入更深一层的递归时,问题规模相比上次递归都应该少
(3)递归的效率不高,递归层次过多会导致内存溢出(在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈贞,每当函数返回,栈就会减一层栈贞。由于栈的大小不是无限的,所以递归的次数过多,会导致栈溢出)。
高阶函数
前言:变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数。
#普通函数
def test_1(a,b):
return a+b
#高阶函数
def test_2(a,b,f):
return f(a)+f(b)
res = test_1(1,-3)
print(res)
res = test_2(1,-3,abs) #把abs这个内置函数当做参数传进去
print(res)