函数
首次发布时间:2020/8/4
最后修改时间:2020/8/4
本系列文章基于 python3 版本
摘要
- 什么是函数
- 如何定义一个函数
- 调用一个函数
- 函数的文档说明
- 函数的参数
- 带参数的函数
- 什么是参数?
- 缺省参数
- 不定长参数
- 调用带有参数的函数
- 什么是函数的返回值
- 函数的嵌套调用
- 局部变量和全局变量
- 局部变量
- 全局变量
- 递归函数
- 匿名函数
- 使用匿名函数
什么是函数?
-
之前学的内容,都是一句一句的从上往下依次执行的
-
并且如果有需要重复用到的代码,要再重新写一下
-
在程序开发的过程中,经常需要某块代码多次执行
-
但是为了提高编写效率,通过代码的重(chong)用,把具有独立功能的代码块,组织成一个小模块,这就是函数
如何定义一个函数
def 函数名():
代码
- 代码示例:
def func():
print('the name of this function is func()')
调用一个函数
- 调用函数通过
函数名()
即可完成调用
def func():
print('the name of this function is func()')
func()
- 输出结果:
the name of this function is func()
定义函数名字遵循大小驼峰命名方法
我习惯用小驼峰
函数的文档说明
def add(a, b):
"对两个数求和"
print(a + b)
add(1, 2)
help(add) # 获取 add 函数的帮助信息
- 输出结果:
3
Help on function add in module __main__:
add(a, b)
对两个数求和
函数的参数
带参数的函数
- 假设我们的函数内的参数是写死的
- 那么,这个函数就只能计算我们写的那两个数的乘积,这个函数也就失去了意义
- 为了让一个函数更通用,比如可以计算任意两数的积,可以定义两个参数,让个两个参数代表任意的两个数字
什么是参数?
- 参数就可以理解为是一个代表性的字符
- 这个字符你可以让它代表 1,也可以代表 2,任意你想让他代表的数字
缺省参数
- 所谓缺省参数,顾名思义,就是在声明函数的某个参数的时候,为之指定一个默认值
- 如果你没有指定该参数,在调用该函数的时候就采用该默认值
注意:带有默认值的参数一定要位于参数列表的最后面
def add(a, b=3):
"对两个数求和"
print('a 是 {}'.format(a))
print('b 是 {}'.format(b))
print('a+b 的和是:{}'.format(a + b))
add(1, 2)
add(1)
- 输出结果:
a 是 1
b 是 2
a+b 的和是:3
a 是 1
b 是 3
a+b 的和是:4
不定长参数
- 有时可能需要一个函数能处理比一开始声明时更多的参数
- 这些参数叫做 不定长参数,声明时 不会命名参数
def funcname([formal_args], *args, **kwargs):
"函数文档说明"
代码
返回值
*args
:存放所有未命名的变量参数,args
为元组
**kwargs
:存放所有未命名的变量参数,**kwargs
接收的是字典格式,即kwargs
是一个字典
def func(item, *args, **kwargs):
print("item 是:{}".format(item))
print("args 是:" + str(args))
print("args 的类型是:" + str(type(args)))
print("args 的元素是:")
for i in args:
print(i)
print("-"*40)
print("kwargs 是:" + str(kwargs))
print("kwargs 的类型是:" + str(type(kwargs)))
print("kwargs 的元素是:")
for k, v in kwargs.items():
print(k + ":" + str(v)) # k 一定是字符串,所以不需要用 str() 转换
# 而 v 有可能是字符串,有可能是数字,所以需要用 str() 转换一下
func(1, 'a', 'b', 'c', name='lisa', age=18) # 注意传递的参数要对应
- 输出结果:
item 是:1
args 是:('a', 'b', 'c')
args 的类型是:<class 'tuple'>
args 的元素是:
a
b
c
----------------------------------------
kwargs 是:{'name': 'lisa', 'age': 18}
kwargs 的类型是:<class 'dict'>
kwargs 的元素是:
name:lisa
age:18
调用带有参数的函数
- 如上面所写的
add()
函数,在调用该函数时,需要传入两个参数
def add(a, b):
"对两个数求和"
print('a 是 {}'.format(a))
print('b 是 {}'.format(b))
print('a+b 的和是:{}'.format(a + b))
add(2, 4) # 调用带参数的函数时,需要在小括号中,传递数据(参数)
- 输出结果:
a 是 2
b 是 4
a+b 的和是:6
-
定义函数时,小括号中的参数,是用来接收参数用的,称为
形参
-
调用函数时,小括号中的参数,是用来传递数据给函数用的,称为
实参
-
大家可以用一下这个网站,它会将运行过程展示出来,能够帮助我们理解程序的运行:
什么是函数的返回值
def add(a, b):
"对两个数求和"
print('a 是 {}'.format(a))
print('b 是 {}'.format(b))
print('a+b 的和是:{}'.format(a + b))
return a+b
print('返回值是:' + str(add(2, 4)))
- 输出结果:
a 是 2
b 是 4
a+b 的和是:6
返回值是:6
- 上面的代码中,
return a+b
就是返回值的过程,返回的是a+b
的值 - 另外,返回值可以是有多个的:
def func():
a = 2
b = 3
return a, b
print(func())
- 输出结果:
(2, 3)
返回的结果是元组类型的
函数的嵌套调用
- 之前讲的 if、while 可以嵌套使用,达到想要的效果
- 函数也是可以嵌套使用,而且是非常常用的
def func1():
print('This is func1()')
def func2():
print('This is the head of func2()')
func1()
print('This is the end of func2()')
func2()
- 输出结果:
This is the head of func2()
This is func1()
This is the end of func2()
局部变量和全局变量
局部变量
def func1():
a = 1
print('a 是 {}'.format(a))
a = 6
print('a 变为了 {}'.format(a))
func1()
def func2():
a = 3
print('a 是 {}'.format(a))
func2()
- 输出结果:
a 是 1
a 变为了 6
a 是 3
- 上面
func1()
和func2()
定义的变量a
就是局部变量 - 局部变量的作用域是有限的
- 比如上面的例子中,变量
a
出了函数func1
或func2
的定义范围,就没用了,不存在了
- 比如上面的例子中,变量
- 所以说,不同函数,可以定义同名的变量,互相不会有影响
- 局部变量,就是为了临时保存数据,需要在函数中定义变量来进行存储
- 关键的一点是,局部变量的作用域仅限于在函数内
全局变量
- 如果一个变量能在一个函数里面使用,又可以在其他函数里面使用,这种变量我们称为全局变量
a = 10
def func1():
global a
print('a 是 {}'.format(a))
a = 6
def func2():
print('a 是 {}'.format(a))
func1()
func2()
- 输出结果:
a 是 10
a 是 6
- 如果要在函数里面修改全局变量的值,必须要声明
global a
- 否则如果直接就赋值的话,会报错
- (系统会认为你在函数内定义了一个局部变量,而该局部变量和全局变量重名了)
- 全局变量能够在所有的函数中进行访问
- 对于不可变类型的全局变量来说,因其指向的数据不能修改,所以不使用
global
时无法修改全局变量(像上面的例子) - 对于可变类型的全局变量来说,因其指向的数据可以修改,所以不使用
global
时也可以修改全局变量(请看下面的例子)
a = [1, 2, 3, 4, 5, 6]
def func1():
print('a 是 {}'.format(a))
a[0] = 6
def func2():
print('a 是 {}'.format(a))
func1()
func2()
- 输出结果:
a 是 [1, 2, 3, 4, 5, 6]
a 是 [6, 2, 3, 4, 5, 6]
- 这里是修改列表 a 的元素,如果要对 a 整个重新赋值
- 就像这样:
a = [6, 5, 4, 3, 2, 1]
- 也是需要声明
global
的,否则也会报错 - 所以我们可以得出一个结论:
- 在函数中不使用
global
声明全局变量时不能修改全局变量, - 本质是不能修改全局变量的指向,即不能将全局变量指向新的数据
- 有点类似于,可以修改对象的值,但是无法修改地址(不声明
global
的情况下)
- 在函数中不使用
递归函数
- 之前说的一个函数可以调用另外一个函数
- 那么函数自己调用自己本身的话,这个函数就是递归函数
- 用途:
- 比如说,计算 6 的阶乘:
1x2x3x4x5x6
def func(num): if num >= 1: result = num * func(num-1) else: result = 1 return result print(func(6))
- 输出结果:
720
- 比如说,计算 6 的阶乘:
如果你学过 c、c++ 或 java 等语言,你可能会有个疑惑
为什么 result 是在if...else...
里面定义的,但是出了if
语句的范围还可以用
因为 Python 中并不是所有语句块都会产生作用域
只有在 Module(模块)、Class(类)、def(函数) 中定义的时候,才会有作用域的概念
详细可以参考这篇文章:Python学习之变量的作用域
- 其实上面的函数内部也可以用循环来实现
def func(num):
result = 1
while num >= 1:
result *= num
num -= 1
return result
print(func(6))
- 输出结果是一样的
匿名函数
-
用
lambda
关键词能创建小型匿名函数 -
这种函数省略了用
def
声明函数的标准步骤 -
语法:
lambda [arg1 [,arg2,.....argn]]: expression
lambda 参数列表 : 返回 [表达式] 变量
- 由于 lambda` 返回的是函数对象(构建的是一个函数对象),所以需要定义一个变量去接收
-
代码实例:
sum = lambda arg1, arg2 : arg1 + arg2
# 调用 sum 函数
print("两个数的和是:{}".format(sum(1, 2)))
- 输出结果:
两个数的和是:3
lambda
只是一个表达式,函数体比 def 简单很多- 仅仅能在
lambda
表达式中封装有限的逻辑进去 lambda
函数拥有自己的命名空间,且不能访问自己参数列表之外或全局命名空间里的参数- 虽然
lambda
函数看起来只能写一行,却不等同于 C 或 C++ 的内联函数- 后者的目的是调用小函数时不占用栈内存从而增加运行效率
lambda
函数能接收任何数量的参数但只能返回一个表达式的值- 匿名函数不能直接调用
print()
,因为lambda
需要一个表达式
使用匿名函数
ladies = [
{"name":"lisa", "age":18},
{"name":"emma", "age":19},
{"name":"penny", "age":17}
]
ladies.sort(key = lambda x : x['name'])
print(ladies)
ladies.sort(key = lambda x : x['age'])
print(ladies)
- 输出结果
[{'name': 'emma', 'age': 19}, {'name': 'lisa', 'age': 18}, {'name': 'penny', 'age': 17}]
[{'name': 'penny', 'age': 17}, {'name': 'lisa', 'age': 18}, {'name': 'emma', 'age': 19}]
对于
sort(key = lambda x : x['name'])
这种写法的理解
可以参考这篇文章:python-文件字符分布
思考
-
用函数实现一个判断用户输入的年份是否是闰年的程序
- 提示:
- 能被 400 整除的年份
- 能被 4 整除,但是不能被 100 整除的年份
- 以上 2 种方法满足一种即为闰年
-
实现方法:
def leapYear(year):
"如果输入的年份是闰年,返回 True,否则返回 False"
if year % 4 == 0:
if year % 100 != 0:
return True
else:
if year % 400 == 0:
return True
else:
return False
else:
return False
print(leapYear(128)) # True
print(leapYear(100)) # False
print(leapYear(400)) # True
print(leapYear(3)) # False
- 输出结果:
True
False
True
False