Python函数

Python函数

前言、

在实际开发中,如果有若干段代码的执行逻辑完全相同,那么阔以考虑将这些代码抽取成一个函数,这样不仅阔以提高代码的重要性,而且条理会更加的清晰,可靠性更高。

1.1、什么是函数

函数是组织好的,可重复使用的,用来实现单一的或者相关联功能的代码段,它能够提高应用的模块化和代码的重复利用率。python提供了很多内建函数,如print(),除此之外,我们还阔以自己创建函数,也就是自定义函数,接下来看一段代码:

1
2
3
print('  * ')
print(' *** ')
print('*****')

上述的代码中,使用了多个print()函数输出了一个三角形。如果需要在一个程序的不同位置输出这个图形,那么每次都是用这个print()函数输出的做法是不可取的。

为了提高编写效率以及代码的重用性,我们阔以把具有独特功能的代码块组织成一个小模块,这就是函数!

1.2、函数的定义和调用

1.2.1、定义函数

在python中,你阔以定义一个自己想要功能的函数,自定义函数的语法格式如下:

1
2
3
4
5
6
def 函数名(参数列表):
"函数_文档字符串"
函数体

return 表达式
基于上述格式,下面对函数定义的规则进行说明:
  • 函数代码块已def开头,后面紧跟的是函数名和圆括号()、
  • 函数名的命名规则跟变量的命名规则是一样的,即只能是字母刚、数字和下划线的任何组合,但不能以数字开头,并且不能和关键字重名、
  • 函数的参数必须放在圆括号中、
  • 函数的第一行语句阔以选择性的使用文档字符来存放函数说明、
  • 函数内容以冒号起始,并且缩进、
  • return表达式结束函数,选择性的返回一个值给调用方,不带表达式的return相当于返回None、

接下来,定义一个能够完整打印信息的函数,如下所示:

1
2
3
4
5
# 接下来,定义一个能够完整打印信息的函数
def print_info():
print('-----------------------------')
print(' 人生可短,洋群满满 ')
print('-----------------------------')

1.2.2、调用函数

定义了函数之后,就相当于有了一段具有特定功能的代码,想要这些代码能够执行,需要调用函数。调用函数的方式很简单,通过“函数名()”即可完成成调用。

例如,调用1.2.1中的函数的代码如下:

1
2
# 定义完函数后,函数是不会自动执行的,需要调用它
print_info()

1.3、 函数的参数

1.3.1、 函数参数的传递

在介绍函数的参数之前,我们先来解决一个问题。现在要求定义一个函数,这个函数用于计算两个数的和,并把计算的结果打印出来。把上述的要求转换为代码,示例如下:

1
2
3
def add():
c = 11+22
print(c)

以上函数的功能是计算11和22的和。此时,无论调用这个函数多少次,得到的结果永远是一样的,而且只计算固定的两个数字的和,使得这个函数的局限性很大。

为了能让你定义的函数更加通用,即计算任意两个数字的和,阔以在定义函数的时候添加两个参数,让两个参数来接收传给函数的值。接下来,通过一个案例来演示下:

1
2
3
4
# 定义接收两个参数的函数
def add(a, b):
c = a+b
print(c)

在上面的例子中,定义了能接收两个参数的函数。其中,a为第一个参数,用于接收函数传递的第一个值;b为第二个参数,接收的是函数传递的第二个数值。这时,如果想调用add函数,则需要给函数的参数传递两个数值,代码如下:

1
2
# 调用带有参数的函数时,需要在小括号中传递数据
add(11, 22)

需要注意的是,如果函数定义了多个参数,那么在调用函数的时候,传递的数据要和定义的参数一一对应。

1.3.2、 默认参数

定义函数时,阔以给函数的参数设置默认值,这个参数就被称为默认参数。当调用函数的时候,由于默认参数在定义时已经被赋值,所以阔以直接忽略,而其它参数是必须要传入值的。如果默认参数没有传入值是,则使用默认的值;如果默认参数传入了值,则使用传入的新值替代。

接下来,演示如下:

1
2
3
4
5
6
7
8
9
# 接下来,定义一个能够完整打印信息的函数
def print_info(name, age = 25):
# 打印任何传入的字符串
print("Name:", name)
print("Age:", age)
print('*************')
# 调用函数
print_info(name='洋群满满')
print_info(name='洋群满满', age=22)

在上述的案例中,定义了一个带有两个参数的函数,其中name参数没有设置默认值,age作为默认参数设置了默认值。在后面的调用函数时,第一个由于只传入了name参数的值,所以程序会使用age参数的默认值;在第二个调用时,同时传入了两个参数的值,所以程序会用传给age参数的新值。

运行结果如下所示:

1
2
3
4
5
6
7
8
9
C:\Python\python.exe D:/Desktop/test/demo.py
Name: 洋群满满
Age: 25
*************
Name: 洋群满满
Age: 22
*************

Process finished with exit code 0

需要注意的是,带有默认值的参数一定要位于参数列表的最后面,否则程序会报错。例如,给print_info()函数添加一个参数sex,放在参数列表的最后面,则会报错如下:

1
2
3
4
5
6
7
C:\Python\python.exe D:/Desktop/test/demo.py
File "D:/Desktop/test/demo.py", line 19
def print_info(name, age = 25, sex):
^
SyntaxError: non-default argument follows default argument

Process finished with exit code 1

1.3.3、 不定长参数

通常在定义一个函数时, 若希望函数能够处理的参数个数能比当初定义的参数个数多,此时可以在函数中使用不定长参数。其基本语法的格式如下:

1
2
3
4
def 函数名([formal_args,] *args, **kwargs):
"函数_文档字符串"
函数体
return 表达式

在上述格式中,函数共有3个参数。其中formal_args为形参(也就是前面所用的参数,如a,b),*args和**kwargs为不定长参数。当调用函数的时候,函数传入的参数个数会优先匹配formal_args参数的格个数。如果传入的参数个数和formal_args参数的个数相同,不定长参数会返回控的元祖或字典;如果传入参数的个数比formal_args参数的个数多,阔以分为如下两种情况:

  • 如果传入的参数没有指定名称,那么*args会以元祖的形式存放这些多余的参数;

  • 如果传入的参数指定了名称,如m=1,那么**kwargs会以字典的形式存放这些被命名的参数,如{m:1}

    为了让大家更好地理解,简单的示例演示下:

1
2
3
4
5
def test(a,b,*args):
print(a)
print(b)
print(args)
test(11, 22)

在上面的示例中,先定义了一个带有多个参数的test函。其中,args为不定长参数。在调用函数是,由于只传入了11和22这两个数,所以这两个数会从左向右依次匹配test函数定义时的参数a和b,此时,args参数没有接收到数据,所以为一个空的元祖。

程序运行结果如下:

1
2
3
4
5
6
C:\Python\python.exe D:/Desktop/test/demo.py
11
22
()

Process finished with exit code 0

如果在调用test函数时,传入了多个参数(这里指的是对于两个参数),情况下又是怎么样的呢?

下面看一段演示的代码:

1
2
3
4
5
def test(a,b,*args):
print(a)
print(b)
print(args)
test(11, 22, 33, 44, 55, 66, 77, 88, 99)

运行结果如下:

1
2
3
4
5
6
C:\Python\python.exe D:/Desktop/test/demo.py
11
22
(33, 44, 55, 66, 77, 88, 99)

Process finished with exit code 0

如果在参数列表的末尾使用**kwargs参数,演示代码如下:

1
2
3
4
5
6
def test(a,b,*args, **kwargs):
print(a)
print(b)
print(args)
print(kwargs)
test(11, 22, 33, 44, 55, 66, 77, 88, 99)

运行的结果如下:

1
2
3
4
5
6
7
C:\Python\python.exe D:/Desktop/test/demo.py
11
22
(33, 44, 55, 66, 77, 88, 99)
{}

Process finished with exit code 0

从两次的运行结果阔以看出,如果在调用test函数时传入多个数值,那么这些数会从左向右依次匹配函数test定义时参数。如果跟formal_args参数的个数匹配完,还有多余的参数,则这些多余的参数会组成一个元祖,和不定长参数args进行匹配。此时,kwargs参数没有接收到数据,所以为一个空字典。

那么思考一下,在调用函数时,在什么情况下传入数据会匹配参数kwargs呢?在上述的示例中,将调用函数的代码进行修改,修改后的代码如下所示:

1
2
3
4
5
6
def test(a,b,*args, **kwargs):
print(a)
print(b)
print(args)
print(kwargs)
test(11, 22, 33, 44, 55, 66, 77, n=88, m=99)

运行结果如下:

1
2
3
4
5
6
7
C:\Python\python.exe D:/Desktop/test/demo.py
11
22
(33, 44, 55, 66, 77)
{'n': 88, 'm': 99}

Process finished with exit code 0

从上述的运行结果阔以看出,如果参数是以键值对的形式传入的,则使用**kwargs参数来接收。

1.4、 函数的返回值

所谓的“返回值”,就是程序中的函数完成一件事情后,最后给调用者的结果。比如,定义了一个函数来获取“洋洋”与“群群”年龄的总和,一旦调用了这个函数,函数就会把得到总和的年龄返回给这个调用者,这个年龄总和就是函数的返回值。在python中,函数的返回值使用return语句来完成的。接下来,用一段示例代码演示一下:

1
2
3
4
5
6
def add(a, b):
c = a+b
return c
# 或者阔以这样写
def add(a, b):
return a+b

在上述的代码中,函数add中包含的return语句,意味着这个函数有一个返回值,其结果就是a加b的结果。

1.5、 函数的四种类型

根据有没有参数和返回值,函数大概阔以分为四种类型:

  1. 函数无参数,无返回值;

  2. 函数无参数,有返回值;

  3. 函数有参数,无返回值;

  4. 函数有参数,有返回值。

    接下来,针对这四种类型的函数进行详细讲解。

1.5.1、 函数无参数,无返回值

无参数,无返回值的函数,既不能接收参数,也没有返回值。

接下来,通过一个打印提示的函数来演示这类函数的使用,如下所示:

1
2
3
4
5
6
7
8
def print_menu():
print('---------------------')
print(' 洋群满满 火锅菜单 ')
print(' 1、羊肉火锅')
print(' 2、牛肉火锅')
print(' 3、猪肉火锅')
print('---------------------')
print_menu()

运行结果如下所示:

1
2
3
4
5
6
7
8
9
C:\Python\python.exe D:/Desktop/test/demo.py
---------------------
洋群满满 火锅菜单
1、羊肉火锅
2、牛肉火锅
3、猪肉火锅
---------------------

Process finished with exit code 0

1.5.2、 函数无参数,有返回值

此类函数不能接受参数,但是阔以返回某个数据,一般情况下,采集数据时会用此类函数。接下来,实例演示下:

1
2
3
4
5
6
7
def get_temperature():
# 这里获取温度的一些过程
# 为了简单起见,先模拟返回一个数据即可
return 24

temperature = get_temperature()
print('当前的温度为:', temperature)

运行结果如下:

1
2
3
4
C:\Python\python.exe D:/Desktop/test/demo.py
当前的温度为: 24

Process finished with exit code 0

1.5.3、 函数有参数,无返回值

在实际开发中,有参数,无返回值类型的函数用的极少,这是因为函数作为功能模块,既然传入了参数,绝大多数情况下是希望使用返回值的。这里,大家对有参数,无返回值的函数有所了解即可,示例代码如下:

1
2
3
4
def test_add(num_one, num_two):
result = num_one + num_two
print('计算结果为', result)
test_add(11,22)

运行结果如下:

1
2
3
4
C:\Python\python.exe D:/Desktop/test/demo.py
计算结果为 33

Process finished with exit code 0

1.5.4、 函数有参数,有返回值

此类函数不仅能接收参数,还阔以返回某个数据,一般情况下,处理数据并需要结果的应用,阔以使用此类函数。接下来,通过一个哪里演示一下:

1
2
3
4
5
6
7
8
9
10
# 计算1~number的累积和
def calculate(number):
result = 0
i = 1
while i<=number:
result = result + i
i += 1
return result
result = calculate(100)
print('1~100的累积和为:',result)

运行结果如下:

1
2
3
4
C:\Python\python.exe D:/Desktop/test/demo.py
1~100的累积和为: 5050

Process finished with exit code 0

1.6、 函数案例—名片管理器

名片管理器是一款生活实用类软件,用来协助管理手机中的所有名片。为了帮助大家在实际应用中学会实用四种类型函数,接下来,我们开发一个名片管理器。这个案例要求使用函数完成各种功能,你并且根据键盘的输入来选择对应的函数完成这些功能。

下面是名片管理器的菜单系统,如下所示:

1
2
3
4
5
6
7
8
9
--------------------------------
洋群满满 名片管理系统 v1.0
1、添加名片
2、删除名片
3、修改名片
4、名查询片
5、获取所有名片信息
6、退出系统
---------------------------------

如上所示,名片管理系统中共有六种功能,通过接收键盘输入的序号响应用户选择的功能。一旦用户输入了“6”, 就会退出系统。

创建一个工程,新建一个python文件,取名为“名片管理系统”, 具体实现步骤如下:

1.6.1、 输出名片管理器的菜单

定义输出菜单功能的函数。考虑到该函数只用来输出信息,并且输出的内容是固定不变的,所以定义一个无参数,无返回值的函数display_menu,具体的代码如下:

1
2
3
4
5
6
7
8
9
10
def display_menu():
print('-'*30)
print(' 洋群满满 名片管理系统 v1.0 ')
print(' 1、添加名片')
print(' 2、删除名片')
print(' 3、修改名片')
print(' 4、名查询片')
print(' 5、获取所有名片信息')
print(' 6、退出系统')
print('-'*30)

使用while循环不间断的输出菜单功能的信息。为了检测程序的可行性,阔以将while的判断条件改为“i<1”,

具体的实现代码如下:

1
2
3
4
i = 0
while i <1:
# 打印菜单
display_menu()

程序运行后,控制台一直不间断的输出菜单的信息。测试完毕后,使用Ctrl + F2停止程序。

1.6.2、获取用户输入的信息

菜单显示后, 用户需要根据提示输入要执行的序号。通过input()函数从键盘接收用户的选择,并且把选择的序号进行返回,所以定义一个无参数,有返回值的函数get_choice(),具体代码如下:

1
2
3
4
# 获取用户的选择
def get_choice():
selected_key = input('请输入您选择的序号:')
return int(selected_key)

在while循环打印菜单以后,调用了get_choice()函数来获取用户输入的信息,具体如下:

1
2
# 等待用户选择
key = get_choice()

运行结果如下:

1
2
3
4
5
6
7
8
9
10
11
C:\Python\python.exe D:/Desktop/test/aa.py
------------------------------
洋群满满 名片管理系统 v1.0
1、添加名片
2、删除名片
3、修改名片
4、名查询片
5、获取所有名片信息
6、退出系统
------------------------------
请入您选择的序号:

1.6.3、 通过获取序号,执行不同的功能

获取序号以后,根据序号的不同执行相应的操作。在while语句的末尾,使用if-else语句根据用户的选择的序号完成相应的功能,具体如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
if key == 1:
pass
elif key == 2:
pass
elif key == 3:
pass
elif key == 4:
pass
elif key == 5:
pass
elif key == 6:
pass
else:
print('您的输入不符合要求或有误,请重新输入!!!')

接下来,在每个条件下来处理该序号对应的功能,这里只介绍“添加名片”和“查询名片”的功能。

  • 添加名片

    要想报存所有名片的信息,需要用到一个列表。在while语句前定义一个空的列表,具体如下:

1
name_list = []

用户选择了序号1,此时应该提示用户输入姓名,然后添加到上述的列表中,因此我们定义一个无参数,无返回值的函数,具体如下:

1
2
3
4
# 添加名片
def add_name():
new_name = input('请输入姓名:')
name_list.append(new_name)

接着在用户选择序号1的时候,调用上述函数实现的添加名片的功能,具体代码如下:

1
2
3
4
5
---省略其他代码---
if key == 1:
add_name()
elif key == 2:
---省略其他代码---

运行程序,控制台输出如图:

1
2
3
4
5
6
7
8
9
10
11
12
C:\Python\python.exe D:/Desktop/test/aa.py
------------------------------
洋群满满 名片管理系统 v1.0
1、添加名片
2、删除名片
3、修改名片
4、名查询片
5、获取所有名片信息
6、退出系统
------------------------------
请输入您选择的序号:1
请输入姓名:洋群满满
  • 查询名片

    用户选择了序号5,此时应该从列表中获取所有的姓名信息,按照固定的格式打印,因此我们定义了一个有参数,无返回值的函数print_all_info(),具体代码如下:

1
2
3
4
5
def print_all_info(temp_list):
print("="*30)
for info in temp_list:
print(info)
print("="*30)

紧接着在用户选择序号5的时候,调用上述方法实现产看所有名片的功能,具体如下:

1
2
3
4
5
---省略其他代码---
elif key == 5:
print_all_info(name_list)
elif key == 6:
---省略其他代码---

运行结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
------------------------------
洋群满满 名片管理系统 v1.0
1、添加名片
2、删除名片
3、修改名片
4、名查询片
5、获取所有名片信息
6、退出系统
------------------------------
请输入您选择的序号:5
==============================
洋群满满
==============================

1.7、 函数的嵌套调用

在一个函数的调用另一个函数,这就是所谓的函数嵌套调用。接下来,我们通过一个示例来演示下:

1
2
3
4
5
6
7
8
9
10
11
def func_one():
print('------func one start------')
print('这里是func_one执行的代码')
print('------func one end------')

def func_two():
print('------func two start------')
func_one()
print('------func two end------')

func_two()

上述示例中,定义了两个函数func_one和func_two,其中func_two函数的内部调用了func_one函数。

具体运行结果如下:

1
2
3
4
5
6
C:\Python\python.exe D:/Desktop/test/demo.py
------func two start------
------func one start------
这里是func_one执行的代码
------func one end------
------func two end------

1.8、 变量作用域

1.8.1、 LEGB原则

Python中,程序的变量并不是在那个位置都是阔以访问的,访问的权限决定于这个变量在那里赋值的。我们先来看一段代码:

1
2
3
4
5
6
7
>>> a = 10
>>> def test():
... a = 20
... print('a的值是%d'%a)
...
>>> test()
a的值是20

上述的代码中有两个变量a,当在test函数中输出变量a的值时,为什么输出的是20,而不是10呢?其实,这就是因为变量作用域不同导致的。

变量的作用域决定了在那一部分程序阔以访问那个特定的变量名称。Python变量的作用域一共分为四种。分别是:

  • L(Local): 函数内的区域,包括局部变量和参数
  • E(Enclosing): 外面的嵌套函数区域,常见的是闭包函数的外层函数
  • G(Global): 全局作用域
  • B(Bulit-in): 内建作用域

Python中变量是采用 L -> E -> G -> B 的规则查找,即Python检索变量的时候,会优先在局部作用域中查找。如果没找到,便会去局部外的区域找( 例如闭包 ), 在找不到就会去全局变量作用域中找,最后再去内建作用域中找。

1.8.2、 全局变量与局部变量

变量的作用域始终是Python学习中一个必须理解掌握的环节,下面我们从局部变量和全局变量开始全面解析Python中变量的作用域。

所谓的局部变量,指的是定义在函数内部的变量。即定义在def函数内部的变量,只能在def函数内部使用,它与函数外具有相同名称的其他变量没有任何关系。不同的函数,阔以定义相同的局部名称,并且各个函数内的变量不会产生影响。示例代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
>>> def test_one():
... number = 100
... print('test_one函数中的number值为:%d'%number)
...
>>> def test_two():
... number = 200
... print('test_two函数中的number值为:%d'%number)
...
>>> test_one()
test_one函数中的number值为:100
>>> test_two()
test_two函数中的number值为:200

局部变量只能在其声明的函数内部访问,而全局变量阔以在整个程序范围内部访问。全局变量是定义在函数外的变量,它拥有全局作用域。

接下来用一个案例来区分全局变量与局部变量,具体代码如下:

1
2
3
4
5
6
7
8
result = 100       # 全局变量
def sum(a, b):
result = a+b # 局部变量
print('函数内部的result的值为:%d' %result) # 这里的result值为局部变量
return result
# 调用sum函数
sum(100, 200)
print('函数外的变量result是全局变量,等于:%d' %result)

运行结果如下:

1
2
3
4
5
C:\Python\python.exe D:/Desktop/test/demo.py
函数内部的result的值为:300
函数外的变量result是全局变量,等于:100

Process finished with exit code 0

1.8.3、 global 和 nonlocal关键字

当内部作用域想修改外部作用域的变量时, 就要用到 global 和 nonlocal 关键字了。下面分别对 global 和 nonlocal 的作用进行介绍。

  • global 关键字

global关键字用来在函数或其他局部作用域中使用全局变量。但是如果不修改全局变量也阔以不使用global关键字。具体代码如下:

1
2
3
4
5
6
7
8
9
10
>>> a = 100
>>> def test():
... a+=100
... print(a)
...
>>> test()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in test
UnboundLocalError: local variable 'a' referenced before assignment

上述的程序报错,提示“在赋值前引用了局部变量 a ”。但是,前面我们明明是阔以阔以在函数中访问全局变量啊?这里为什么会出错呢?啊哦!

这就是Python与其他语言的不同之处了, 在Python中,如果在函数内部对全局变量a进行修改,Python会把全局变量a当做局部变量, 而在进行“a+=100”之前,我们是没有声明局部变量a的, 因此,会出现上述的错误提示。

为了使全局变量生效,我们阔以在函数内使用global关键字进行声明,下面,我们对程序进行修改,代码入下:

1
2
3
4
5
6
7
8
>>> a = 100
>>> def test():
... global a
... a+=100
... print(a)
...
>>> test()
200

这下,程序不但没有报错,而且成功对全局变量a进行了修改。

  • nonlocal关键字

    nonlocal 是在Python 3.0 中新增的关键字,Python 2.x 不提供支持。使用nonlocal关键字阔以在一个嵌套的函数中修改嵌套作用域中的变量。接下来,看一个例子:

1
2
3
4
5
6
7
8
9
>>> def func():
... count = 1
... def func_in():
... count = 2
... func_in()
... print(count)
...
>>> func()
1

上面的程序中,在嵌套的func_in函数中,对变量count进行了赋值,同样会创建一个新的变量,而非使用count=1 语句中的count,如果要修改嵌套作用域中的count,就要使用nonlocal关键字了,示例代码如下:

1
2
3
4
5
6
7
8
9
10
>>> def func():
... count = 1
... def func_in():
... nonlocal count
... count = 2
... func_in()
... print(count)
...
>>> func()
2

上述的代码中,在func_in()函数中使用了nonlocal关键字,就会告诉Python在func函数中使用嵌套作用域中的变量count,因此对变量count进行修改时,会直接影响到嵌套作用域中的count变量值,程序最后也就输出2了!

!!!注意!!!

使用global关键字修饰的变量之前是阔以不存在的,而使用nonlocal关键字修饰的变量在嵌套作用域中必须已经存在。

1.9 、 递归函数与匿名函数

1.9.1、 递归函数

通过前面的学习阔以知道,一个函数的内部是阔以调用其他函数的。如果在一个函数的内部调用了函数本身,那么这个函数我们就成为递归函数。

接下来,通过一个计算阶乘 n! = 12…*n的例子来演示递归函数的使用,具体代码如下:

1
2
3
4
5
6
7
8
9
# 递归函数
def func(count):
if count ==1:
result = 1
else:
result = func(count-1)*count
return result
number = int(input('请输入一个正整数:'))
print("%d! ="%number, func(number))

运行结果如下:

1
2
3
4
5
C:\Python\python.exe D:/Desktop/test/demo.py
请输入一个正整数:5
5! = 120

Process finished with exit code 0

1.9.2、 匿名函数

简单的来说,匿名函数就是没有名称的函数,也就是不再使用def语句定义的函数。如果要声明匿名函数,则需要使用lambda关键字,匿名函数的声明格式如下:

1
lambda [arg1[,arg2,...argn]]: experssion

上述格式中,”[arg1[,arg2,…argn]]“表示的函数的参数,”expression“表示的是函数的表达式。例如,下面声明的匿名函数。

1
2
3
4
add = lambda a, b: a+b
# 调用add函数
print("运行结果:", add(11, 22))
print("运行结果:", add(22, 22))

运行结果如下:

1
2
3
4
5
C:\Python\python.exe D:/Desktop/test/demo.py
运行结果: 33
运行结果: 44

Process finished with exit code 0

需要注意的是,使用lambda声明的匿名函数能接收任意数量的参数,但只能返回一个表达式的值。匿名函数不能直接调用print()函数,这是因为lambda需要一个表达式。

在某些场景下,匿名函数非常有用。假设之前我们对两个数进行运算,如果希望声明的函数支持所有运算,阔以将匿名函数作为函数的参数进行传递。接下来,我们通过一个示例演示:

1
2
3
4
5
6
7
8
9
# 匿名函数-1
def func(a,b,c, aa):
print("a = %d"%a)
print("b = %d"%b)
print("c = %d"%c)
print("result = ", aa(a,b))
func(11,22,33, lambda x, y,i:x+y-i)
print('-'*20)
func(11,22,33, lambda x, y,i:x-y+i)

运行结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
C:\Python\python.exe D:/Desktop/test/demo.py
a = 11
b = 22
c = 33
result = 0
--------------------
a = 11
b = 22
c = 33
result = 22

Process finished with exit code 0

除此之外,匿名函数还通常作为内置函数的参数来使用,接下来看一个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
# 匿名函数-2
students = [
{'name':'yangyang', 'age':'23'},
{'name':'qunqun', 'age':'24'},
{'name':'yangyangqunqun', 'age':'47'}
]
# 按name排序
students.sort(key=lambda x:x['name'])
print("按name排序后的结果为:", students)

# 按age排序
students.sort(key=lambda x:x['age'])
print("按name排序后的结果为:", students)

运行结果如下:

1
2
3
4
5
C:\Python\python.exe D:/Desktop/test/demo.py
按name排序后的结果为: [{'name': 'qunqun', 'age': '24'}, {'name': 'yangyang', 'age': '23'}, {'name': 'yangyangqunqun', 'age': '47'}]
按name排序后的结果为: [{'name': 'yangyang', 'age': '23'}, {'name': 'qunqun', 'age': '24'}, {'name': 'yangyangqunqun', 'age': '47'}]

Process finished with exit code 0

!!!注意!!!

与def定义的函数对比,lambda定义的函数有很多不同的地方。

  1. def定义的函数是有名称的,而lambda定义的函数没有函数名称,这是最明显的区别之一;
  2. lambda定义的函数通常会返回一个对象或者一个表达式,它不会将返回的结果赋值给一个变量,而def定义的函数就阔以;
  3. lambda定义的函数中只有一个表达式,函数体比def定义的函数简单很多,而def定义的函数的函数体是一个语句;
  4. lambda表达式的冒号后面只能有一个表达式,而def定义的函数则阔以有很多个;
  5. 像if或for等语句不能用于lambda定义的函数中,而def定义的函数阔以;
  6. lambda一般用来定义简单的函数,而def定义复杂的函数;
  7. lambda定义的函数不能共享给别的程序调用,而def定义的函数则阔以被调用。

1.10、 日期时间函数

Python 有很多处理日期和时间的方法,其中转换日期格式是最为常见的,Python提供了time和calendar模块用于格式化日期和时间。

1.10.1、 日期函数

在Python中,通常有如下几种方式表示时间:

  1. 时间戳
  2. 格式化的时间字符串
  3. 时间元祖(struct_time)
1.10.1.1、时间戳

通常来讲,时间戳表示的是从1970年1月1日00:00:00 开始按秒计算的偏移量。返回时间戳的函数主要有time(),clock()等。

接下来,通过一个案例来演示:

1
2
3
import time   # 引入time模块
ticks = time.time()
print("当前的时间戳为:", ticks)

运行的结果为:

1
2
3
4
C:\Python\python.exe D:/Desktop/test/demo.py
当前的时间戳为: 1608983774.0507226

Process finished with exit code 0
1.10.1.2、格式化的时间字符串

我们阔以使用time模块的strftime函数来格式化日期,其定义的格式如下:

1
time.strftime(format[ ,t])

接下来,通过一个案例来演示strftime函数的使用,示例如下:

1
2
3
4
5
6
7
8
9
10
import time   # 引入time模块
ticks = time.time()
print("当前的时间戳为:", ticks)
# 格式化成2020-12-26 20:05:49 形式
print(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))
# 格式化成Sat Dec 26 20:07:55 2020 形式
print(time.strftime("%a %b %d %H:%M:%S %Y", time.localtime()))
# 将格式字符串转换成时间戳
time_word = "Sat Dec 26 20:07:55 2020"
print(time.mktime(time.strptime(time_word, "%a %b %d %H:%M:%S %Y")))

运行结果如下:

1
2
3
4
5
6
7
C:\Python\python.exe D:/Desktop/test/demo.py
当前的时间戳为: 1608984646.544159
2020-12-26 20:10:46
Sat Dec 26 20:10:46 2020
1608984475.0

Process finished with exit code 0

为了大家更全面的了解日期格式化,接下来,通过一张表来列举Python中的时间日期格式化符号,表如下:

格式化字符串 含义
%y 两位数的年份表示(00~99)
%Y 四位数的年份表示(000~9999)
%m 月份(01~12)
%d 月内中的一天
%H 24小时制小时数(0~23)
%I 12小时制小时数(01~12)
%M 分钟数(00~59)
%S 秒(00~59)
%a 本地简化的星期名称
%A 本地完整的星期名称
%b 本地简化的月份名称
%B 本地完整的月份名称
%c 本地相应的日期表示和时间表示
%j 年内的一天(001~336)
%p 本地的A.M.或者P.M.等价符
%U 一年中的星期数(00~53),星期一为星期的开始
%w 星期(0~6),星期日为星期的开始
%x 本地相应的星期表示
%X 本地相应的时间表示
%Z 当前的时区的名称
%% %本身
1.10.1.3、 时间元祖(struct_time)

返回struct_time的函数主要有gmtime()、localtime()和striptime(),struct_time元祖共有九个元素,我们通过一张表来列出元祖中的这些元素,如下表所示:

序号 字段 含义 取值范围
0 tm_year 4位数的年份 例如:2020
1 tm_mon 表示月份 1~12
2 tm_mday 表示天数 1~31
3 tm_hour 表示小时数 0~23
4 tm_min 表示分钟数 0~59
5 tm_sec 表示秒数 0~61(60和61是闰秒)
6 tm_wday 表示星期数 0~6(0是周一)
7 tm_yday 表示一年中的第几天 1~366(儒略历)
8 tm_isdst 决定是否为夏令时的标识符 允许的值为-1/0/1

另外,time模块还提供了很多其他的函数, 例如,sleep()函数用于推迟调用线程的运行,接下来,通过一张表来列举time模块的其他函数,具体如下表:

序号 函数名 含义
1 time.altzone 返回格林威治西部的夏令时地区的偏移秒数。如果该地区在格林威治东部会返回负值(如西欧,包括英国)。对夏令时启用地区才能使用
2 time.asctime([tupletime]) 接收时间元祖并返回一个可读的形式为“Tue Dec 11 18:07:14 2020”(2020年 12月 11日 周二 18点 07分 14秒)的24个字符的字符串
3 time.clock() 用于浮点数计算的秒数返回当前的CPU时间。用于衡量不同程序的耗时,比time.time()更有用
4 time.ctime([secs]) 作用相当于asctime(localtime(secs)),未提供参数相当于asctime()
5 time.gmtime([secs]) 将一个时间戳转换为UTC时区(0时区)的struct_time,可选的参数sec表示从1970-1-1以来的秒数。其默认值为time.time(),函数返回time.struct_time类型的对象。注:t.tm_isdst始终为0
6 time.localtime([secs]) 类似gmtime(),作用是格式化时间戳为本地的时间。 如果sec参数未输入,则以当前时间为转换标准。 DST (Daylight Savings Time) flag (-1, 0 or 1) 是否是夏令时。
7 time.mktime(tupletime) 执行与gmtime(), localtime()相反的操作,它接收struct_time对象作为参数,返回用秒数来表示时间的浮点数。如果输入的值不是一个合法的时间,将触发 OverflowError 或 ValueError。
8 time.sleep(secs) 推迟调用线程的运行,可通过参数secs指秒数,表示进程挂起的时间。
9 time.strftime(fmt[,tupletime]) 接收以时间元组,并返回以可读字符串表示的当地时间,格式由参数 format 决定。
10 time.strptime(str,fmt=’%a %b %d %H:%M:%S:%Y’) 根据指定的格式把一个时间字符串解析为时间元组。
11 time.time() 返回当前时间的时间戳(1970纪元后经过的浮点秒数)。
12 time.tzset() 根据环境变量TZ重新初始化时间相关设置。标准TZ环境变量格式:std offset [dst [offset [,start[/time], end[/time]]]]

除此之外,time模块还包含了以下两个非常重要的属性具体如下表:

序号 名称 含义
1 time.timezone 是当时时区(未启动夏令时)距离格林威治的偏移秒数(>0,美洲;<=0,大部分欧洲,亚洲,非洲)
2 time.tzname 包含一对根据情况的不同而不的字符串,分别是带夏令时的本地时区名称和不带名称的

1.10.2、 日历函数

calendar模块中提供了非常多的方法来处理年历和月历。例如2020年12月份的日历具体代码实现如下:

1
2
3
4
5
import calendar

calendar_march = calendar.month(2020,12)
print("以下时2020年12月份的日历:")
print(calendar_march)

运行结果如下:

1
2
3
4
5
6
7
8
9
C:\Python\python.exe D:/Desktop/test/demo.py
以下时2020年12月份的日历:
December 2020
Mo Tu We Th Fr Sa Su
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31

除此之外, calendar模块还提供了很多内置函数,具体如下表:

序号 名称 含义
1 calendar.calendar(year,w=2,I=1,c=6,m=3) 以多行字符串形式返回一年的日历,w每个单元格宽度,默认2,内部已做处理,最小宽度为2,l每列换l行,默认为1,内部已做处理,至少换行1行,c表示月与月之间的间隔宽度,默认为6,内部已做处理,最小宽度为2,m表示将12个月分为m列
2 calendar.firstweekday() 返回一周的第一天,0是星期一,…,6为星期日
3 calendar.isleap(year) 判断指定是否是闰年,闰年为True,平年为False
4 calendar.ieapdays(y1,y2) 返回y1y2年份之间的闰年数量,y1y2皆为年份。包括起始年,不包括结束年:
5 calendar.month(year,month,w=2,I=1) 返回一个月的日历的多行文本字符串。year指定年份,month指定月份,w每个单元格宽度,默认0,内部已做处理,最小宽度为2,l每列换l行,默认为0,内部已做处理,至少换行1行
6 calendar.monthcalendar(year,month) 返回一个月中天数列表(不是当前月份的天数为0),按周划分,为一个二维数组。包括月份开始那周的所有日期和月份结束那周的所有日期
7 calendar.monthrange(year, month) 返回一个由一个月第一个天的星期与当前月的天数组成的元组
8 calendar.prcal(year,w=2,I=1,c=6,m=3) 打印一年的日历,w每个单元格宽度,默认0,内部已做处理,最小宽度为2,l每列换l行,默认为0,内部已做处理,至少换行1行,c表示月与月之间的间隔宽度,默认为6,内部已做处理,最小宽度为2,m表示将12个月分为m列
9 calendar.prmonth(year,month,w=2,I=1) 打印一个月的日历,theyear指定年份,themonth指定月份,w每个单元格宽度,默认0,内部已做处理,最小宽度为2,l每列换l行,默认为0,内部已做处理,至少换行1行
10 calendar.setfirstweekday(firstweekday) 指定一周的第一天,0是星期一,…,6为星期日
11 calendar.timegm(tupletime) 该函数将一个元组时间变成时间戳。
12 calendar.weekday(year,month, day) 获取指定日期为星期几

1.11、 随机数函数

Python中的random模块用于生成随机数,它提供了很多函数。接下来,针对常见的随机数函数进行讲解,具体如下:

1.11.1、 random.random()

返回0-1之间的浮点数N,范围为0<= N <=1.0。

接下来,通过一个示例来演示:

1
2
3
4
5
import random
# 生成第一个随机数
print('random():', random.random())
# 生成第二个随机数
print('random():', random.random())

运行结果如下:

1
2
3
4
5
C:\Python\python.exe D:/Desktop/test/demo.py
random(): 0.9414705808484405
random(): 0.5730106704826693

Process finished with exit code 0

1.11.2、 random.uniform(a,b)

返回a与b之间的随机浮点数N,范围为[a,b]。 如果a的值小于b的值,则生成的随机浮点数N的取值范围为:a<= N <=b; 如果a的值大于b的值,则生成的随机浮点数N的取值范围为:b<= N <=a。示例如下:

1
2
3
import random
print('random():', random.uniform(50,100))
print('random():', random.uniform(100,50))

运行结果如下所示:

1
2
3
4
5
C:\Python\python.exe D:/Desktop/test/demo.py
random(): 94.65991375247847
random(): 60.57936076593128

Process finished with exit code 0

1.11.3、 random.randint(a,b)

返回一个随机整数N,N的取值范围为:a<= N <=b。 需要注意的是,a和b的取值必须是整数,并且a的值一定要小于b的值, 示例代码如下:

1
2
3
4
5
6
7
import random
# 生成随机数的范围为[12,20]
print('random.randint:', random.randint(12,20))
# 生成随机数的范围为[20,20], 结果永远为20
print('random.randint:', random.randint(12,20))

#print('random.randint:', random.randint(20,12))# 该语句是错误的,a的值必须小于b

结果如下:

1
2
3
4
5
C:\Python\python.exe D:/Desktop/test/demo.py
random.randint: 16
random.randint: 19

Process finished with exit code 0

1.11.4、 random.randrange([start], stop[,step])

返回指定递增基数集合中的一个随机数,基数默认值为1。其中,start参数用于指定范围内的开始值,其包含在范围内;end参数用于指定范围内的结束值,其不包含在范围内;step表示递增的基数。

上述这些参数必须为整数。例如:random.randrange(10, 100, 2)相当于从[10,12,14……96,98]中获取一个随机数。

1.11.5、 random.choice(sequence)

从sequence中返回一个随机的元素。其中,sequence参数可以是列表、元祖或者字符串。示例代码如下:

1
2
3
4
import random
print('random.choice', random.choice('洋群满满'))
print('random.choice', random.choice(['洋','群满','满']))
print('random.choice', random.choice(('洋群', '满满')))

运行结果如下:

1
2
3
4
5
6
C:\Python\python.exe D:/Desktop/test/demo.py
random.choice: 满
random.choice: 洋
random.choice: 洋群

Process finished with exit code 0

1.11.6、 random.shuffle(x,[,random])

用于将列表中的元素打乱顺序,俗称为洗牌。示例代码如下:

1
2
3
4
import random
demo_list = ['python','洋群满满', 'java','C', 'javascript']
random.shuffle(demo_list)
print(demo_list)

运行结果如下:

1
2
3
4
C:\Python\python.exe D:/Desktop/test/demo.py
['python', 'C', '洋群满满', 'java', 'javascript']

Process finished with exit code 0

1.11.7、 random.sample(sequence, k)

从指定序列中随机获取K个元素作为一个片段返回,sample函数不会修改原有序列。示例代码如下:

1
2
3
4
5
import random
num_list = [1,2,3,4,5,6,7,8,9,10]
slice = random.sample(num_list,5) # 从num_list中随机获取5个元素,作为一个片段返回
print(slice)
print(num_list) # 原有的序列顺序未改变

运行结果如下:

1
2
3
4
5
C:\Python\python.exe D:/Desktop/test/demo.py
[6, 3, 1, 5, 9]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

Process finished with exit code 0

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!