目录
函数是执行特定任务的一段代码,程序通过将一段代码定义成函数,并为该函数指定一个函数名,这样即可在需要的时候多次调用这段代码。因此,函数是代码复用的重要手段。
在Python 中,函数的应用非常广泛,前面已经接触过很多函数,比如 input() 、print()、range()、len() 函数等等,这些都是 Python 的内置函数,可以直接使用。
除了可以直接使用的内置函数外,Python 还支持自定义函数,即将一段有规律的、可重复使用的代码定义成函数,从而达到一次编写、多次调用的目的,这被叫做用户自定义函数。
学习函数需要重点掌握函数的定义以及函数调用的方法。
1. 调用函数
Python内置了很多有用的函数,我们可以直接调用。
要调用一个函数,需要知道函数的名称和参数,比如求绝对值的函数abs,只有一个参数。可以直接从Python的官方网站查看文档:
http://docs.python.org/3/library/functions.html#abs
也可以在交互式命令行通过help(abs)查看abs函数的帮助信息。
示例:在python交互式命令行查看abs函数帮助
C:\Desktop\py>python Python 3.8.7 (tags/v3.8.7:6503f05, Dec 21 2020, 17:59:51) [MSC v.1928 64 bit (AMD64)] on win32 Type "help", "copyright", "credits" or "license" for more information. >>> help(abs) Help on built-in function abs in module builtins: abs(x, /) Return the absolute value of the argument. |
函数调用的基本语法格式如下所示:
函数名([形参值]) |
调用函数的时候,如果传入的参数数量不对,会报TypeError的错误。
如果传入的参数数量是对的,但参数类型不能被函数所接受,也会报TypeError的错误,并且给出错误信息。所以需要注意,传入参数的个数和类型一定要对应。
示例代码: 调用abs函数计算绝对值:
#!/usr/bin/python3 print(abs(120)) print(abs(-120)) |
示例代码: 调用int()函数将字符串类型数据转为整型数据返回:
#!/usr/bin/python3 data=input("请输入一个整数:") int_data=int(data) print("你输入的整数:%d" % (int_data)) |
2. 定义一个函数
定义函数的简单规则:
(1)、函数代码块以 def 关键词开头,后接函数标识符名称和圆括号 ()。
(2)、任何传入参数和自变量必须放在圆括号中间,圆括号之间可以用于定义参数。
(3)、函数的第一行语句可以选择性地使用文档字符串—用于存放函数说明。
(4)、函数内容以冒号起始,并且缩进。
(5)、return [表达式] 结束函数,选择性地返回一个值给调用方。不带表达式的return相当于返回 None。
Python 定义函数使用 def 关键字,一般格式如下:
def 函数名(形参列表): #由零条到多条可执行语句组成的代码块 [return [返回值]] |
其中,用 [] 括起来的为可选择部分,即可以使用,也可以省略。
默认情况下,参数值和参数名称是按函数声明中定义的顺序匹配起来的。
示例: 使用函数来输出"Hello World!"
#!/usr/bin/python3#定义函数 def hello() : print("Hello World!") #调用函数 hello() |
示例: 设计求和函数
#!/usr/bin/python3 def my_sum(x,y): return x+y data1=int(input("请输入整数1:")) data2=int(input("请输入整数2:")) #调用函数 data_sum=my_sum(data1,data2) print("data_sum=%d" % (data_sum)) |
函数体内部的语句在执行时,一旦执行到return时,函数就执行完毕,并将结果返回。因此,函数内部通过条件判断和循环可以实现非常复杂的逻辑。
如果没有return语句,函数执行完毕后也会返回结果,只是结果为None,return None可以简写为return。
3. 函数参数传递
3.1 函数必要参数
函数必要参数,也称位置参数,指的是必须按照正确的顺序将实际参数传到函数中,调用函数时传入实际参数的数量和位置都必须和定义函数时保持一致,否则 Python 解释器会抛出 TypeError 异常,并提示缺少必要的位置参数。
示例代码:
#!/usr/bin/python3 #指定参数的默认值 def cal_max(x, y): if(x>y): return x else: return b a=int(input("the first num:")) b=int(input("the first num:")) print(cal_max(a)) |
结果:
the first num:2 the first num:8 Traceback (most recent call last): File "run.py", line 11, in <module> print(cal_max(a)) TypeError: cal_max() missing 1 required positional argument: 'y' |
3.2 函数关键字参数
前面的例子代码,使用函数时所用的参数都是位置参数,即传入函数的实际参数必须与形式参数的数量和位置对应。
Python还支持关键字参数,这样可以避免牢记参数位置的麻烦,令函数的调用和参数传递更加灵活方便。
关键字参数是指使用形式参数的名字来确定输入的参数值。通过此方式指定函数实参时,不再需要与形参的位置完全一致,只要将参数名写正确即可。
因此,Python 函数的参数名应该具有更好的语义,这样程序可以立刻明确传入函数的每个参数的含义。示例代码:
#!/usr/bin/python3 def print_func(data,str): print("你传入的整数:%d" % (data)) print("你传入的字符串:%s" % (str)) return #按照位置传参 print_func(1234,"hello world") #按照关键字传参 print_func(data=1234,str="hello world") #按照关键字传参 print_func(str="hello world",data=1234) #关键字和位置参数混合传参 print_func(1234,str="hello world") #print_func(str="hello world",1234) 这样传参是错误的,混合传参要按照顺序(有关键字的情况下) |
如果希望在调用函数时混合使用关键字参数和位置参数,则关键字参数必须位于位置参数之后,在关键字参数之后的只能是关键字参数。
3.3 函数默认参数
前面说过,在调用函数时,如果传入的参数与函数不匹配或者没有传入参数,解释器会抛出异常。
为了解决这个问题,Python 允许为参数设置默认值,即在定义函数时,直接给形式参数指定一个默认值(定义的时候就指定一个默认值),这样的话,即便调用函数时没有给拥有默认值的形参传递参数,该参数可以直接使用定义函数时设置的默认值。
定义带有默认值参数的函数,其语法格式如下:
def 函数名(...,形参名=默认值): 代码块 |
在使用上面格式定义函数时,有默认值的参数必须放在没有默认值参数的最后,否则会产生语法错误。示例代码:
#!/usr/bin/python3 #指定参数的默认值 def print_func(data=666,str="欢迎学习Python编程"): print("你传入的整数:%d" % (data)) print("你传入的字符串:%s" % (str)) return #使用默认参数 print_func() #使用自定义参数 print_func(7890) #传入的参数覆盖默认的参数 #使用自定义参数 print_func(str="哈哈哈") #传入的参数覆盖默认的参数 |
在 Python 中,可以使用“函数名.__defaults__”查看函数的默认值参数的当前值,其返回值是一个元组。示例代码:
#!/usr/bin/python3 #指定参数的默认值 def print_func(data=666,str="欢迎学习Python编程"): print("你传入的整数:%d" % (data)) print("你传入的字符串:%s" % (str)) return print(print_func.__defaults__) ''' #使用默认参数 print_func() #使用自定义参数 print_func(7890) #传入的参数覆盖默认的参数 #使用自定义参数 print_func(str="哈哈哈") #传入的参数覆盖默认的参数 ''' |
结果:
(666, '欢迎学习Python编程') |
3.4 函数不定长参数
有时候需要一个函数能处理比当初声明时更多的参数,这些参数叫做不定长参数,和上面讲的几种参数不同,声明时不会命名。
Python提供了2种方法实现不定长参数:
(1)在形参名前加一个*, 表示接受任意多的参数
(2)在形参名前加两个**, 表示接受任意的关键字参数
第一种: 函数参数带一个*号
语法格式如下:
def 函数名([参数列表,] *不定长参数): 代码块 |
加了星号 * 的参数会以元组(tuple)的形式导入,存放所有未命名的变量参数。示例代码:
#!/usr/bin/python3 def print_func(str, *args_list): print("你传入的参数:",str) print("传入的可变长参数:",args_list) return print_func("hello world","python","PHP","C/C++") print_func(1,2,3,4,5) |
结果:
你传入的参数: hello world 传入的可变长参数: ('python', 'PHP', 'C/C++') 你传入的参数: 1 传入的可变长参数: (2, 3, 4, 5) |
示例代码:
#!/usr/bin/python3 def print_func(*args_list): print("传入的可变长参数:",args_list) return print_func("hello world","python","PHP","C/C++") print_func(1,2,3,4,5) |
结果:
传入的可变长参数: ('hello world', 'python', 'PHP', 'C/C++') 传入的可变长参数: (1, 2, 3, 4, 5) |
第二种: 函数参数带两个*号
语法格式如下:
def 函数名([参数列表,] **不定长参数): 代码块 |
加了两个星号 ** 的参数会以字典的形式导入。示例代码:
#!/usr/bin/python3 def print_func(**args_list): print("传入的可变长参数:",args_list)#变成键值对(字典) return print_func(a="hello world",b="python",c="PHP",d="C/C++") |
结果:
传入的可变长参数: {'a': 'hello world', 'b': 'python', 'c': 'PHP', 'd': 'C/C++'} |
4. 匿名函数
python 使用 lambda来创建匿名函数。所谓匿名,就是不再使用 def 语句这样标准的形式定义一个函数。lambda 函数的语法只包含一个语句,格式如下:
lambda [参数1 [,参数1,.....参数n]]:函数代码块 |
lambda函数的语法说明
(1). lambda 只是一个表达式,函数体比 def 简单很多。
(2). lambda的主体是一个表达式,而不是一个代码块。仅仅能在lambda表达式中封装有限的逻辑进去。
(3). lambda 函数拥有自己的命名空间,且不能访问自己参数列表之外或全局命名空间里的参数。
虽然lambda函数看起来只能写一行,却不等同于C或C++的内联函数,后者的目的是调用小函数时不占用栈内存从而增加运行效率。
匿名函数限制,只能有一个表达式,不用写return,返回值就是该表达式的结果。
用匿名函数不必担心函数名冲突,匿名函数也是一个函数对象,也可以把匿名函数赋值给一个变量,再利用变量来调用该函数。示例代码:
#!/usr/bin/python3 # 函数说明 sum = lambda arg1, arg2: arg1 + arg2 #前面是参数列表,后面是语句块 # 调用sum函数 print ("相加后的值为 : ", sum( 10, 20 )) print ("相加后的值为 : ", sum( 20, 20 )) |
示例代码:
#!/usr/bin/python3 #函数说明 print_func = lambda arg1, *arg2: print("传入的参数:",arg1, arg2) ''' print_func = lambda arg1, *arg2: print("传入的参数:",arg1, arg2) ''' #错误的语法格式:匿名函数的语句块要直接跟在冒号后面 #调用函数 print_func(1,2,3,4,5,6) |
结果:
传入的参数: 1 (2, 3, 4, 5, 6) |
5. return语句
Python中,用 def 语句创建函数时,可以用 return 语句指定应该返回的值,该返回值可以是任意类型。需要注意的是,return 语句在同一函数中可以出现多次,但只要有一个得到执行,就会直接结束函数的执行。
函数中,使用 return 语句的语法格式如下:
return [返回值] |
其中,返回值参数可以指定,也可以省略不写(不写将返回: 空值 None)。
None(N 必须大写)是一个特殊的常量。和 False 不同,它不表示 0,也不表示空字符串,而表示没有值,也就是空值。
None 常用于 assert、判断以及函数无返回值的情况。在前面章节中一直使用 print() 函数输出数据,其实该函数的返回值就是 None。因为它的功能是在屏幕上显示文本,根本不需要返回任何值,所以 print() 就返回 None。
对于所有没有 return 语句的函数定义,Python 都会在末尾加上 return None,使用不带值的 return 语句(也就是只有 return 关键字本身),那么就返回 None。
6. 关于函数形参可更改与不可更改对象
在 python 中,strings, tuples, 和 numbers 是不可更改的对象,而 list,dict 等则是可以修改的对象。-->列表和字典是可更改的,其余不可更改。
不可变类型:变量赋值 a=5 后再赋值 a=10,这里实际是新生成一个 int 值对象 10,再让 a 指向它,而 5 被丢弃,不是改变a的值,相当于新生成了a。
可变类型:变量赋值 la=[1,2,3,4] 后再赋值 la[2]=5 则是将 list la 的第三个元素值更改,本身la没有动,只是其内部的一部分值被修改了。
6.1 python 函数的参数传递
不可变类型:类似 c++ 的值传递,如 整数、字符串、元组。如fun(a),传递的只是a的值,没有影响a对象本身。比如在 fun(a)内部修改 a 的值,只是修改另一个复制的对象,不会影响 a 本身。
可变类型:类似 c++ 的引用传递,如 列表,字典。如 fun(la),则是将 la 真正的传过去,修改后fun外部的la也会受影响。
python 中一切都是对象,严格意义我们不能说值传递还是引用传递,我们应该说传不可变对象和传可变对象。
示例代码:python 传不可变对象
#!/usr/bin/python3 def func(data): data=2 print("data=",data) a=100 func(a) print("a=",a) #这里打印a的值还是100 |
结果:
data= 2 a= 100 |
示例代码: 传递可更改对象
可变对象在函数里修改了参数,那么在调用这个函数的函数里,原始的参数也被改变了
#!/usr/bin/python3 def func(list): list[1]="666" print("list=",list) list_data=["1","2","3","4","5"] func(list_data) #调用函数 print("list_data=",list_data) |
结果:
list= ['1', '666', '3', '4', '5'] list_data= ['1', '666', '3', '4', '5'] |
7. 局部变量与全局变量
7.1 局部变量
在程序中定义一个变量时,这个变量是有作用范围的,变量的作用范围被称为它的作用域。
变量的作用域指程序代码能够访问该变量的区域,如果超过该区域,将无法访问该变量。根据定义变量的位置(有效范围),可以将变量分为局部变量和全局变量。
局部变量: 是指在函数内部定义并使用的变量,它只在函数内部有效。
每个函数在执行时,系统都会为该函数分配一块“临时内存空间”,所有的局部变量都被保存在这块临时内存空间内。当函数执行完成后,这块内存空间就被释放,这些局部变量也会释放,因此离开函数之后就不能再访问局部变量,否则解释器会抛出 NameError 错误。示例代码:
#!/usr/bin/python3 def func(): data=1234 print("data=",data) func() #调用函数 print("data=",data) #错误: 无法访问局部变量 |
结果:
Traceback (most recent call last): File "run.py", line 8, in <module> print("data=",data) #错误: 无法访问局部变量 NameError: name 'data' is not defined |
7.2 全局变量
全局变量: 是指函数内外都可以访问的变量。
即全局变量既可以在各个函数的外部使用,也可以在各函数内部使用。
定义全局变量的方式:
(1)在函数体外定义的变量,一定是全局变量,示例代码:
#!/usr/bin/python3 data=1234 def func(): print("data=",data) func() #调用函数 print("data=",data) |
结果:
data= 1234 data= 1234 |
(2)在函数体内使用 global 关键字定义全局变量,示例代码:
#!/usr/bin/python3 def func(): global data #使用global关键字修饰变量时,不能赋值 data=1234 print("data=",data)
func() #调用函数 print("data=",data) |
结果:
data= 1234 data= 1234 |
8. 局部函数
Python 支持在函数体内定义函数,这种被放在函数体内定义的函数称为局部函数。在默认情况下,局部函数对外部是隐藏的,局部函数只能在其封闭(enclosing)函数内有效,其封闭函数也可以返回局部函数,以便程序在其他作用域中使用局部函数。
如果封闭函数没有返回局部函数,那么局部函数只能在封闭函数内部调用。
如果封闭函数将局部函数返回,且程序使用变量保存了封闭函数的返回值,那么这些局部函数的作用域就会被扩大,程序可以使用封闭函数的返回值自由地调用局部函数,就像使用全局函数一样。示例代码:
#!/usr/bin/python3 def func(): def sum(a,b): #定义局部函数 return a+b return sum #返回局部函数 a=func() #调用全局函数 print("求和:", a(12,45)) #通过全局函数的返回值,调用内部的局部函数 |
结果:
求和: 57 |
下一篇: