为了提高编写的效率以及代码的重用,所以把具有独立功能的代码块组织为一个小模块,这就是函数
一、定义函数
~~~
def 函数名():
代码
Demo(一个打印‘hello word的使用’):
def function():
print("hello word")
~~~
二、调用
函数名()
Demo:
function()
注:我们python是一个非编译语言,我们在调用函数时要在函数的定义下边,否则会报错
在使用过程中调用函数名加上一个小括号就可以了,如果不加()那么是一个函数的引用,不能够成功调用
三、函数的分类
函数根据有没有参数,有没有返回值,可以相互组合,一共有4种
无参数,无返回值
此类函数,不能接收参数,也没有返回值,一般情况下,打印提示灯类似的功能,使用这类的函数
无参数,有返回值
此类函数,不能接收参数,但是可以返回某个数据,一般情况下,像采集数据,用此类函数
有参数,无返回值
此类函数,能接收参数,但不可以返回数据,一般情况下,对某些变量设置数据而不需结果时,用此类函数
有参数,有返回值
此类函数,不仅能接收参数,还可以返回某个数据,一般情况下,像数据处理并需要结果的应用,用此类函数
四、文档说明
def demo(a,b):
"用来计算2个数的和"
return a+b
可以执行
help(demo)
查看函数的相关说明,一般情况函数的文档说明包含:参数说明、函数作用、返回值三部分
五、变量
1)局部变量
局部变量,就是在函数内部定义的变量
其作用范围是这个函数内部,即只能在这个函数中使用,在函数的外部是不能使用的
因为其作用范围只是在自己的函数内部,所以不同的函数可以定义相同名字的局部变量(打个比方,把你、我是当做成函数,把局部变量理解为每个人手里的手机,你可有个iPhone8,我当然也可以有个iPhone8了, 互不相关)
局部变量的作用,为了临时保存数据需要在函数中定义变量来进行存储
当函数调用时,局部变量被创建,当函数调用完成后这个变量就不能够使用了
比如在讲到for循环的时候
for i in range(10):
print(i)
i 就是相当于局部变量 在其他位置不能使用只能在for循环中使用。
在函数中局部变量就是在函数中定义的变量
2)全局变量
如果一个变量,既能在一个函数中使用,也能在其他的函数中使用,这样的变量就是全局变量
打个比方:有2个兄弟 各自都有手机,各自有自己的小秘密在手机里,不让另外一方使用(可以理解为局部变量);但是家里的电话是2个兄弟都可以随便使用的(可以理解为全局变量)
全局变量可以说在函数外面定义的变量,所有函数都可以使用到
demo:
# 定义全局变量
a =100
deftest1():
print(a)# 虽然没有定义变量a但是依然可以获取其数据
deftest2():
print(a)# 虽然没有定义变量a但是依然可以获取其数据
# 调用函数
test1()
test2()
全局变量能够在所有的函数中进行访问
全局变量和局部变量名字相同
demo:
a = 100 #定义全局变量
def func():
a = 10 # 定义局部变量,和全局变量名相同
print(a) #函数内在输出时是局部的10,而不是100
print(a) #函数外面输出100 局部变量在函数外面无法访问
局部变量会覆盖全局变量,在局部变量所在的块或者函数内,对变量的操作不影响全局变量的值,全局变量不起作用,在局部变量所在的代码块或函数外部,全局变量才起作用。
这就是变量作用域的问题。
如果我们想在函数中修改全局变量而不是局部变量,那么我们需要使用global进行声明
a = 100 #定义全局变量
def func():
global a # 声明使用全局变量
a = 10
print(a) #在输出时是局部的10
print(a) # 输出10 global 声明后将全部变量进行修改
六、参数
为了让一个函数更通用,即想让它计算哪两个数的和,就让它计算哪两个数的和,在定义函数的时候可以让函数接收数据,就解决了这个问题,这就是 函数的参数(接收到的参数就可以当做局部变量来使用,python中没有指针,参数的传递有两种方式:值传递、引用传递。一般我们用的是引用传递)
参数在这里有分为形参和实参。我们可以理解形参就是函数上面定义时接收的变量名,实参就是调用的时候传递的参数。一般我们讲到的参数就是指的形参,即函数定义时的参数。
1)形参
demo:
#定义一个函数作用是进行两个数进行相加,在这里a,b就是参数
def add2num(a,b):
c = a +b
pring(c)
add2num(10,20) #调用函数计算两个数的和
我们的python解析器首先去定义函数add2num,然后在进行时调用函数,调用时传递两个参数,分别给a,b
然后程序会走到c = a + b进行计算,最后打印结果。
* 缺省参数(在形参中默认有值的参数,称之为缺省参数)
调用函数时,缺省参数的值如果没有传入,则取默认值。
demo:
下例会打印默认的age,如果age没有被传入:
def printinfo(name, age=35):
# 打印任何传入的字符串
print("name: %s"% name)
print("age %d"% age)
# 调用printinfo函数
printinfo(name="miki")
# 在函数执行过程中 age去默认值35
printinfo(age=9,name="miki")
以上实例输出结果:
name: miki
age:35
name: miki
age:9
注意:带有默认值的参数一定要位于参数列表的最后面
* 不定长参数(有时可能需要一个函数能处理比当初声明时更多的参数, 这些参数叫做不定长参数,声明时不会命名。)
def functionname([formal_args,] *args, **kwargs):
"""函数_文档字符串"""
function_suite
return[expression]
加了星号(*)的变量args会存放所有未命名的变量参数,args为元组
而加**的变量kwargs会存放命名参数,即形如key=value的参数, kwargs为字典.
deffun(a, b, *args, **kwargs):
"""可变参数演示示例"""
print("a =%d"% a)
print("b =%d"% b)
print("args:")
print(args)
print("kwargs: ")
forkey, valueinkwargs.items():
print("key=%s"% value)
fun(1,2,3,4,5, m=6, n=7, p=8)# 注意传递的参数对应
以上打印结果:
a =1
b =2
args:(3,4,5)
kwargs:
p =8
m =6
n =7
第二次传递参数:
c = (3,4,5)
d = {"m":6,"n":7,"p":8}
fun(1,2, *c, **d)# 注意元组与字典的传参方式
打印结果
a =1
b =2
args:(3,4,5)
kwargs:
p =8
m =6
n =7
第三次调用
fun(1,2, c, d)# 注意不加星号与上面的区别
打印结果:
a =1
b =2
args:
((3,4,5), {'p':8,'m':6,'n':7})
kwargs:
注:如果很多个值都是不定长参数,那么这种情况下,可以将缺省参数放到 *args的后面, 但如果有**kwargs的话,**kwargs必须是最后的
2)实参
实参就是函数在调用时小括号里面写入的参数,实参可以传递一个值,也可以是一个引用。在后面的学习里形参还可以传递一个对象,或者是一个函数。因为他们都是一个引用,可以当做一个参数来传递。
注意在使用中传递的参数实参数据类型要和接收方形参的数据类型一致。
七、返回值
所谓“返回值”,就是程序中函数完成一件事情后,最后给调用者的结果
想要在函数中把结果返回给调用者,需要在函数中使用return
如下示例:
def add2num(a, b):
c = a+b
return c
在返回后的数据一般情况我的会使用或者保存的这个值,那么我们可以用一个变量名去接收
#调用函数,顺便保存函数的返回值
result = add2num(100,98)
print(result)
1)返回多个值
有的函数返回的结果不仅仅只有一个,那么我们应该怎么做呢?
defdivid(a, b):
shang = a//b
yushu = a%b
return shang, yushu#默认是元组
result = divid(5,2)
print(result)# 输出(2, 1)
返回的值是一个元组,我们可以进行拆包
a,b = divid(5,2)
print(a) #打印结果为2
print(b) #打印结果为1
注:返回的数值一定要一一对应才可以正常拆包
return后面可以是元组,列表、字典等,只要是能够存储多个数据的类型,就可以一次性返回多个数据
deffunction():
# return [1, 2, 3]
# return (1, 2, 3)
return{"num1":1,"num2":2,"num3":3}
2)多个return
defcreate_nums():
print("---1---")
return1# 函数中下面的代码不会被执行,因为return除了能够将数据返回之外,还有一个隐藏的功能:结束函数
print("---2---")
return2
print("---3---")
一个函数中可以有多个return语句,但是只要有一个return语句被执行到,那么这个函数就会结束了,因此后面的return没有什么用处。
def create_nums(num):
print("---1---")
if num ==100:
print("---2---")
return num+1# 函数中下面的代码不会被执行,因为return除了能够将数据返回之外,还有一个隐藏的功能:结束函数
else:
print("---3---")
return num+2
result1 = create_nums(100)
print(result1)# 打印101
result2 = create_nums(200)
print(result2)# 打印202
八、匿名函数
用lambda关键词能创建小型匿名函数。这种函数得名于省略了用def声明函数的标准步骤。
lambda函数的语法只包含一个语句,如下:
lambda[arg1 [,arg2,.....argn]]:expression
如下实例:
sum =lambda arg1, arg2: arg1 + arg2
#调用sum函数
print("Value of total : ", sum(10,20))
print("Value of total : ", sum(20,20))
以上实例输出结果:
Value of total :30
Value of total :40
Lambda函数能接收任何数量的参数但只能返回一个表达式的值
匿名函数不能直接调用print,因为lambda需要一个表达式
lambda函数一般情况下会当做一个参数来传递,比如做字典的排序。或者放到高级函数中使用,后面会有讲到。
九、函数的嵌套调用
在一个函数中嵌套调用另外一个函数,就是函数的嵌套调用。
deftestB():
print('---- testB start----')
print('这里是testB函数执行的代码...(省略)...')
print('---- testB end----')
deftestA():
print('---- testA start----')
testB()
print('---- testA end----')
testA()
运行结果:
---- testA start----
---- testB start----
这里是testB函数执行的代码...(省略)...
---- testB end----
---- testA end----
十、递归
如果一个函数在内部不调用其它的函数,而是自己本身的话,这个函数就是递归函数。
举个例子,我们来计算阶乘 n! = 1 * 2 * 3 * ... * n
def func(num):
if num > 1:
reault = num * func(num-1)
else:
reault = 1
return reault
func(5)
十一、闭包
闭包也具有提高代码可复用性的作用。后边讲到的装饰器就是用到闭包的原理
# 定义一个函数
def test(number):
# 在函数内部再定义一个函数,并且这个函数用到了外边函数的变量,那么将这个函数以及用到的一些变量称之为闭包
def test_in(number_in):
print("in test_in 函数, number_in is %d"% number_in)
return number+number_in #number_in其实是一个函数的引用,是把函数的引用当做参数来传递
# 其实这里返回的就是闭包的结果
return test_in #返回一定是内部函数的引用,不能带有小括号
# 给test函数赋值,这个20就是给参数
ret = test(20) # 在这里执行的是test函数,然后将test_in函数的引用返回,重新赋值给ret
# 注意这里的100其实给参数
print(ret(100)) #在这里使用的ret(100) 相当于test_in(100) 也就相当于 test(20)(100) 最终返回的是 20+100
#注 意这里的200其实给参数
print(ret(200)) #在这里使用的ret(100) 相当于test_in(200) 也就相当于 test(20)(200) 最终返回的是 20+200
由于闭包引用了外部函数的局部变量,则外部函数的局部变量没有及时释放,消耗内存