当前位置:   article > 正文

Python------函数_def test(a,b,*args,**kwargs)

def test(a,b,*args,**kwargs)

Python------函数

Authors: 洋群满满

前言、

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

1.1、什么是函数

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

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

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

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

1.2、函数的定义和调用

1.2.1、定义函数

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

def 函数名(参数列表):
    "函数_文档字符串"
    函数体
    
    return 表达式
  • 1
  • 2
  • 3
  • 4
  • 5
	基于上述格式,下面对函数定义的规则进行说明:
  • 1
  • 函数代码块已def开头,后面紧跟的是函数名和圆括号()、

  • 函数名的命名规则跟变量的命名规则是一样的,即只能是字母刚、数字和下划线的任何组合,但不能以数字开头,并且不能和关键字重名、

  • 函数的参数必须放在圆括号中、

  • 函数的第一行语句阔以选择性的使用文档字符来存放函数说明、

  • 函数内容以冒号起始,并且缩进、

  • return表达式结束函数,选择性的返回一个值给调用方,不带表达式的return相当于返回None、

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

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

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
1.2.2、调用函数

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

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

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

1.3、 函数的参数

1.3.1、 函数参数的传递

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

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

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

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

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

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

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

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

1.3.2、 默认参数

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

​ 接下来,演示如下:

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

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

​ 运行结果如下所示:

C:\Python\python.exe D:/Desktop/test/demo.py
Name: 洋群满满
Age: 25
*************
Name: 洋群满满
Age: 22
*************

Process finished with exit code 0
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

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

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
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
1.3.3、 不定长参数

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

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

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

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

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

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

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

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

​ 程序运行结果如下:

C:\Python\python.exe D:/Desktop/test/demo.py
11
22
()

Process finished with exit code 0
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

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

​ 下面看一段演示的代码:

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

​ 运行结果如下:

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

Process finished with exit code 0

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

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

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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

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

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

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

​ 运行结果如下:

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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

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

1.4、 函数的返回值

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

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

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

1.5、 函数的四种类型

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

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

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

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

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

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

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

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

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

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

​ 运行结果如下所示:

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

Process finished with exit code 0
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
1.5.2、 函数无参数,有返回值

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

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

temperature = get_temperature()
print('当前的温度为:', temperature)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

​ 运行结果如下:

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

Process finished with exit code 0
  • 1
  • 2
  • 3
  • 4
1.5.3、 函数有参数,无返回值

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

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
  • 2
  • 3
  • 4
1.5.4、 函数有参数,有返回值

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

# 计算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
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

​ 运行结果如下:

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

Process finished with exit code 0
  • 1
  • 2
  • 3
  • 4

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

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

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

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

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

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

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

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

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

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

具体的实现代码如下:

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

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

1.6.2、获取用户输入的信息

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

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

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

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

​ 运行结果如下:

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

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

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

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('您的输入不符合要求或有误,请重新输入!!!')
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

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

  • 添加名片

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

name_list = []
  • 1

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

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

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

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

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

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

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

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

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

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

​ 运行结果如下:

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

1.7、 函数的嵌套调用

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

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()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

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

​ 具体运行结果如下:

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

1.8、 变量作用域

1.8.1、 LEGB原则

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

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

​ 上述的代码中有两个变量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函数内部使用,它与函数外具有相同名称的其他变量没有任何关系。不同的函数,阔以定义相同的局部名称,并且各个函数内的变量不会产生影响。示例代码如下:

>>> 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
  • 9
  • 10
  • 11
  • 12

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

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

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
  • 6
  • 7
  • 8

​ 运行结果如下:

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

Process finished with exit code 0
  • 1
  • 2
  • 3
  • 4
  • 5
1.8.3、 global 和 nonlocal关键字

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

  • global 关键字

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

>>> 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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

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

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

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

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

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

  • nonlocal关键字

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

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

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

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

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

!!!注意!!!

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

1.9 、 递归函数与匿名函数

1.9.1、 递归函数

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

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

# 递归函数
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
  • 6
  • 7
  • 8
  • 9

​ 运行结果如下:

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

Process finished with exit code 0

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
1.9.2、 匿名函数

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

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

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

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

​ 运行结果如下:

C:\Python\python.exe D:/Desktop/test/demo.py
运行结果: 33
运行结果: 44

Process finished with exit code 0
  • 1
  • 2
  • 3
  • 4
  • 5

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

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

# 匿名函数-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

​ 运行结果如下:

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

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

# 匿名函数-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
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

​ 运行结果如下:

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
  • 1
  • 2
  • 3
  • 4
  • 5
!!!注意!!!

​ 与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()等。

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

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

​ 运行的结果为:

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

Process finished with exit code 0
  • 1
  • 2
  • 3
  • 4
1.10.1.2、格式化的时间字符串

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

time.strftime(format[ ,t])
  • 1

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

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
  • 8
  • 9
  • 10

​ 运行结果如下:

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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

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

格式化字符串含义
%y两位数的年份表示(00~99)
%Y四位数的年份表示(000~9999)
%m月份(01~12)
%d月内中的一天
%H24小时制小时数(0~23)
%I12小时制小时数(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元祖共有九个元素,我们通过一张表来列出元祖中的这些元素,如下表所示:

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

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

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

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

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

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

import calendar

calendar_march = calendar.month(2020,12)
print("以下时2020年12月份的日历:")
print(calendar_march)
  • 1
  • 2
  • 3
  • 4
  • 5

​ 运行结果如下:

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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

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

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

1.11、 随机数函数

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

1.11.1、 random.random()

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

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

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
  • 2
  • 3
  • 4
  • 5
1.11.2、 random.uniform(a,b)

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

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

  • 1
  • 2
  • 3
  • 4

​ 运行结果如下所示:

C:\Python\python.exe D:/Desktop/test/demo.py
random(): 94.65991375247847
random(): 60.57936076593128

Process finished with exit code 0
  • 1
  • 2
  • 3
  • 4
  • 5
1.11.3、 random.randint(a,b)

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

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
  • 6
  • 7

​ 结果如下:

C:\Python\python.exe D:/Desktop/test/demo.py
random.randint: 16
random.randint: 19

Process finished with exit code 0
  • 1
  • 2
  • 3
  • 4
  • 5
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参数可以是列表、元祖或者字符串。示例代码如下:

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

​ 运行结果如下:

C:\Python\python.exe D:/Desktop/test/demo.py
random.choice: 满
random.choice: 洋
random.choice: 洋群

Process finished with exit code 0
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
1.11.6、 random.shuffle(x,[,random])

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

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
  • 2
  • 3
  • 4
1.11.7、 random.sample(sequence, k)

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

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
  • 1
  • 2
  • 3
  • 4
  • 5
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/588910
推荐阅读
相关标签
  

闽ICP备14008679号